diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..ae581573 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "tarscpp"] + path = tarscpp + url = https://github.com/TarsCloud/TarsCpp.git +[submodule "thirdparty/rapidjson"] + path = thirdparty/rapidjson + url = https://github.com/Tencent/rapidjson.git diff --git a/AdminRegistryServer/AdminReapThread.cpp b/AdminRegistryServer/AdminReapThread.cpp new file mode 100644 index 00000000..3023a4fc --- /dev/null +++ b/AdminRegistryServer/AdminReapThread.cpp @@ -0,0 +1,112 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "AdminReapThread.h" + +extern TC_Config * g_pconf; + +AdminReapThread::AdminReapThread() +: _terminate(false) +, _timeout(150) +{ +} + +AdminReapThread::~AdminReapThread() +{ + if (isAlive()) + { + terminate(); + notifyAll(); + getThreadControl().join(); + } +} + + +int AdminReapThread::init() +{ + TLOGDEBUG("begin AdminReapThread init"<((*g_pconf).get("/tars/reap", "10")); + //最小值保护 + _updateInterval = _updateInterval < 5 ? 5 : _updateInterval; + + //管理主控心跳超时时间 + _timeout = TC_Common::strto((*g_pconf)["/tars/reap"]); + _timeout = _timeout < 5 ? 5 : _timeout; + + //是否关闭更新管理主控心跳时间,一般需要迁移时,设置此项为Y + _heartBeatOff = (*g_pconf).get("/tars/reap", "N") == "Y"?true:false; + + _db.updateRegistryInfo2Db(_heartBeatOff); + _db.loadIPPhysicalGroupInfo(); + + TLOGDEBUG("AdminReapThread init ok."<getNow(); + time_t tLastQueryServer = 0; + time_t tNow; + while(!_terminate) + { + try + { + tNow = TNOW; + //更新心跳 + if(tNow - tLastUpdateTime >= _updateInterval) + { + tLastUpdateTime = tNow; + _db.updateRegistryInfo2Db(_heartBeatOff); + _db.loadIPPhysicalGroupInfo(); + } + + //轮询心跳超时的主控 + if(tNow - tLastQueryServer >= _timeout) + { + tLastQueryServer = tNow; + _db.checkRegistryTimeout(_timeout); + } + + TC_ThreadLock::Lock lock(*this); + timedWait(100); //ms + } + catch(exception & ex) + { + TLOGERROR("AdminReapThread exception:" << ex.what() << endl); + } + catch(...) + { + TLOGERROR("AdminReapThread unknown exception:" << endl); + } + } +} + + + diff --git a/AdminRegistryServer/AdminReapThread.h b/AdminRegistryServer/AdminReapThread.h new file mode 100644 index 00000000..5da2dc77 --- /dev/null +++ b/AdminRegistryServer/AdminReapThread.h @@ -0,0 +1,74 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __AMINREAP_THREAD_H__ +#define __AMINREAP_THREAD_H__ + +#include +#include "util/tc_thread.h" +#include "DbProxy.h" + +using namespace tars; + +/** + * 用于执行定时操作的线程类 + */ +class AdminReapThread : public TC_Thread, public TC_ThreadLock +{ +public: + /* + * 初始化函数 + */ + AdminReapThread(); + + /* + * 析构函数 + */ + ~AdminReapThread(); + + /* + * 结束线程 + */ + void terminate(); + + /** + * 初始化 + */ + int init(); + + /** + * 轮询函数 + */ + virtual void run(); + +protected: + //线程结束标志 + bool _terminate; + + //数据库操作 + DbProxy _db; + + //心跳更新时间间隔 + int _updateInterval; + + //服务心跳超时时间 + int _timeout; + + //服务心跳包开关 + bool _heartBeatOff; +}; + +#endif diff --git a/AdminRegistryServer/AdminRegistryImp.cpp b/AdminRegistryServer/AdminRegistryImp.cpp new file mode 100644 index 00000000..f41b6a4a --- /dev/null +++ b/AdminRegistryServer/AdminRegistryImp.cpp @@ -0,0 +1,908 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "AdminRegistryImp.h" +#include "ExecuteTask.h" +#include "servant/Application.h" + +extern TC_Config * g_pconf; + +void AdminRegistryImp::initialize() +{ + TLOGDEBUG("begin AdminRegistryImp init"<getCommunicator()->stringToProxy("tars.tarspatch.PatchObj"); + + TLOGDEBUG("AdminRegistryImp init ok."<addTaskReq(taskReq); + + return 0; +} + +int AdminRegistryImp::getTaskRsp(const string &taskNo, TaskRsp &taskRsp, tars::TarsCurrentPtr current) +{ + //优先从内存中获取 + bool ret = ExecuteTask::getInstance()->getTaskRsp(taskNo, taskRsp); + if (ret) + { + // TLOGDEBUG("AdminRegistryImp::getTaskRsp taskNo:" << taskNo << " from running time, ret:" << ret < &taskRsp, tars::TarsCurrentPtr current) +{ + TLOGDEBUG("AdminRegistryImp::getTaskHistory application:" << application << "|serverName:" << serverName < &info, tars::TarsCurrentPtr current) +{ + return _db.setTaskItemInfo(itemNo, info); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +/// +vector AdminRegistryImp::getAllApplicationNames(string & result, tars::TarsCurrentPtr current) +{ + TLOGDEBUG("AdminRegistryImp::getAllApplicationNames enter"< AdminRegistryImp::getAllNodeNames(string & result, tars::TarsCurrentPtr current) +{ + map mNodes = _db.getActiveNodeList(result); + map::iterator it; + vector vNodes; + + TLOGDEBUG("AdminRegistryImp::getAllNodeNames enter" <first); + } + + return vNodes; +} + +int AdminRegistryImp::getNodeVesion(const string &nodeName, string &version, string & result, tars::TarsCurrentPtr current) +{ + try + { + TLOGDEBUG("AdminRegistryImp::getNodeVesion enter" <(g_pconf->get("/tars/nodeinfo","3000")); + nodePrx->tars_set_timeout(timeout)->tars_ping(); + + result = "succ"; + TLOGDEBUG("AdminRegistryImp::pingNode name:"<getIp()<<":"<getPort()<shutdown(result); + } + catch(TarsException & ex) + { + TLOGERROR( "AdminRegistryImp::shutdownNode '"<<( name + "' exception:" + ex.what())< > AdminRegistryImp::getAllServerIds(string & result, tars::TarsCurrentPtr current) +{ + TLOGDEBUG("AdminRegistryImp::getAllServerIds:"<getIp()<<":"<getPort()<getIp() << ":" << current->getPort() < server; + server = _db.getServers(application, serverName, nodeName,true); + if(server.size() == 0) + { + TLOGERROR("AdminRegistryImp::getServerState "<<(" '" + application + "." + serverName + "_" + nodeName + "' no config")<setResponse(false); + + NodePrxCallbackPtr callback = new GetServerStateCallbackImp(nodePrx, application, serverName, nodeName, state, current); + nodePrx->async_getStateInfo(callback, application, serverName); + } + catch(TarsException & e ) + { + current->setResponse(true); + string s = e.what(); + if(s.find("server function mismatch exception") != string::npos) + { + ServerState stateInNode = nodePrx->getState(application, serverName, result); + state.presentStateInNode = etos(stateInNode); + state.processId = nodePrx->getServerPid(application, serverName, result); + } + TLOGERROR("AdminRegistryImp::getServerState "<<"'" + application + "." + serverName + "_" + nodeName<<"|"<< e.what() <getIp() << ":" << current->getPort() <getIp() << ":" << current->getPort() < server; + server = _db.getServers(application, serverName, nodeName, true); + + //判断是否为dns 非dns才需要到node启动服务 + if(server.size() != 0 && server[0].serverType == "tars_dns") + { + TLOGINFO(" '" + application + "." + serverName + "_" + nodeName + "' is tars_dns server"<getIp() << ":" << current->getPort() <setResponse(false); + NodePrxCallbackPtr callback = new StartServerCallbackImp(application, serverName, nodeName, current); + nodePrx->async_startServer(callback, application, serverName); + } + + return iRet; + } + catch(TarsSyncCallTimeoutException& tex) + { + current->setResponse(true); + iRet = EM_TARS_CALL_NODE_TIMEOUT_ERR; + TLOGERROR("AdminRegistryImp::startServer '"<<(application + "." + serverName + "_" + nodeName+ "' TarsSyncCallTimeoutException:" + tex.what())<setResponse(true); + iRet = EM_TARS_NODE_NOT_REGISTRY_ERR; + TLOGERROR("AdminRegistryImp::startServer '"<<(application + "." + serverName + "_" + nodeName + "' TarsNodeNotRegistryException:" + re.what())<setResponse(true); + result = string(__FUNCTION__) + " '" + application + "." + serverName + "_" + nodeName + + "' TarsException:" + ex.what(); + TLOGERROR("AdminRegistryImp::startServer '"<<(application + "." + serverName + "_" + nodeName + "' TarsException:" + ex.what())<getIp() << ":" << current->getPort() < server; + server = _db.getServers(application, serverName, nodeName, true); + + //判断是否为dns 非dns才需要到node启动服务 + if(server.size() != 0 && server[0].serverType == "tars_dns") + { + TLOGINFO("AdminRegistryImp::stopServer '" + application + "." + serverName + "_" + nodeName + "' is tars_dns server"<getIp() << ":" << current->getPort() << "|" << iRet <getIp() << ":" << current->getPort() <setResponse(false); + NodePrxCallbackPtr callback = new StopServerCallbackImp(application, serverName, nodeName, current); + nodePrx->async_stopServer(callback, application, serverName); + } + + return iRet; + } + catch(TarsSyncCallTimeoutException& tex) + { + current->setResponse(true); + iRet = EM_TARS_CALL_NODE_TIMEOUT_ERR; + TLOGERROR("AdminRegistryImp::stopServer '"<<(application + "." + serverName + "_" + nodeName+ "' TarsSyncCallTimeoutException:" + tex.what())<setResponse(true); + iRet = EM_TARS_NODE_NOT_REGISTRY_ERR; + TLOGERROR("AdminRegistryImp::stopServer '"<<(application + "." + serverName + "_" + nodeName+ "' TarsNodeNotRegistryException:" + re.what())<setResponse(true); + TLOGERROR("AdminRegistryImp::stopServer '"<<(application + "." + serverName + "_" + nodeName+ "' TarsException:" + ex.what())<getIp() << ":" << current->getPort() < server; + server = _db.getServers(application, serverName, nodeName, true); + + //判断是否为dns 非dns才需要到node停止、启动服务 + if(server.size() != 0 && server[0].serverType == "tars_dns") + { + isDnsServer = true; + } + else + { + NodePrx nodePrx = _db.getNodePrx(nodeName); + iRet = nodePrx->stopServer(application, serverName, result); + } + TLOGDEBUG("AdminRegistryImp::restartServer stop|"<< application << "." << serverName << "_" << nodeName << "|" << current->getIp() << ":" << current->getPort() <getIp() << ":" << current->getPort() <startServer(application, serverName, result); + } + } + catch(TarsSyncCallTimeoutException& tex) + { + result = "AdminRegistryImp::restartServer '" + application + "." + serverName + "_" + nodeName + + "' TarsSyncCallTimeoutException:" + tex.what(); + + iRet = EM_TARS_CALL_NODE_TIMEOUT_ERR; + } + catch(TarsNodeNotRegistryException& re) + { + result = "AdminRegistryImp::restartServer '" + application + "." + serverName + "_" + nodeName + + "' TarsNodeNotRegistryException:" + re.what(); + + iRet = EM_TARS_NODE_NOT_REGISTRY_ERR; + } + catch(TarsException & ex) + { + result += "AdminRegistryImp::restartServer '" + application + "." + serverName + "_" + nodeName + + "' TarsException:" + ex.what(); + iRet = EM_TARS_UNKNOWN_ERR; + } + TLOGERROR( result << endl); + } + return iRet; +} + +int AdminRegistryImp::notifyServer(const string & application, const string & serverName, const string & nodeName, const string &command, string &result, tars::TarsCurrentPtr current) +{ + TLOGDEBUG("AdminRegistryImp::notifyServer: " << application << "." << serverName << "_" << nodeName << "|" << current->getIp() << ":" << current->getPort() <setResponse(false); + NodePrxCallbackPtr callback = new NotifyServerCallbackImp(current); + nodePrx->async_notifyServer(callback, application, serverName, command); + return EM_TARS_SUCCESS; + } + catch(TarsSyncCallTimeoutException& tex) + { + current->setResponse(true); + iRet = EM_TARS_CALL_NODE_TIMEOUT_ERR; + TLOGERROR("AdminRegistryImp::notifyServer '"<<(application + "." + serverName + "_" + nodeName + + "' TarsSyncCallTimeoutException:" + tex.what())<setResponse(true); + iRet = EM_TARS_NODE_NOT_REGISTRY_ERR; + TLOGERROR("AdminRegistryImp::notifyServer '"<<(application + "." + serverName + "_" + nodeName + + "' TarsNodeNotRegistryException:" + re.what())<setResponse(true); + TLOGERROR("AdminRegistryImp::notifyServer '"<<(application + "." + serverName + "_" + nodeName + + "' TarsException:" + ex.what())<"]; + + TLOGDEBUG("AdminRegistryImp::batchPatch " + << reqPro.appname + "." + reqPro.servername + "_" + reqPro.nodename << "|" + << reqPro.binname << "|" + << reqPro.version << "|" + << reqPro.user << "|" + << reqPro.servertype << "|" + << reqPro.patchobj << "|" + << reqPro.md5 <<"|" + << reqPro.ostype + << endl); + + //获取patch包的文件信息和md5值 + string patchFile; + string md5; + int iRet = _db.getInfoByPatchId(reqPro.version, patchFile, md5); + if (iRet != 0) + { + TLOGERROR("AdminRegistryImp::batchPatch"<< ", get patch tgz error:" << reqPro.version << endl); + return EM_TARS_GET_PATCH_FILE_ERR; + } + + //让tarspatch准备发布包 + iRet = _patchPrx->preparePatchFile(reqPro.appname, reqPro.servername, patchFile); + if (iRet != 0) + { + TLOGERROR("AdminRegistryImp::batchPatch"<< ", prepare patch file error:" << patchFile << endl); + return EM_TARS_PREPARE_ERR; + } + + reqPro.md5 = md5; + + iRet = EM_TARS_UNKNOWN_ERR; + int defaultTime = 3000; + NodePrx proxy; + try + { + proxy = _db.getNodePrx(reqPro.nodename); + int timeout = TC_Common::strto(g_pconf->get("/tars/nodeinfo","10000")); + + current->setResponse(false); + NodePrxCallbackPtr callback = new PatchProCallbackImp(reqPro, proxy, defaultTime, current); + proxy->tars_set_timeout(timeout)->async_patchPro(callback, reqPro); + } + catch(TarsSyncCallTimeoutException& tex) + { + current->setResponse(true); + result = tex.what(); + iRet = EM_TARS_CALL_NODE_TIMEOUT_ERR; + TLOGERROR("AdminRegistryImp::batchPatch " << reqPro.appname + "." + reqPro.servername + "_" + reqPro.nodename <<"|ret."<setResponse(true); + result = re.what(); + iRet = EM_TARS_NODE_NOT_REGISTRY_ERR; + TLOGERROR("AdminRegistryImp::batchPatch "<< reqPro.appname + "." + reqPro.servername + "_" + reqPro.nodename <<"|ret."<setResponse(true); + result = ex.what(); + iRet = EM_TARS_NODE_NOT_REGISTRY_ERR; + TLOGERROR("AdminRegistryImp::batchPatch "<< reqPro.appname + "." + reqPro.servername + "_" + reqPro.nodename <<"|ret."<setResponse(true); + result = "Unknown Exception"; + TLOGERROR("AdminRegistryImp::batchPatch " << reqPro.appname + "." + reqPro.servername + "_" + reqPro.nodename <<"|ret."<getIp() << ":" << current->getPort() <setResponse(false); + NodePrxCallbackPtr callback = new GetPatchPercentCallbackImp(application, serverName, nodeName, current); + nodePrx->async_getPatchPercent(callback, application, serverName); + } + catch(TarsSyncCallTimeoutException& tex) + { + current->setResponse(true); + TLOGERROR( "AdminRegistryImp::getPatchPercent: " << application + "." + serverName + "_" + nodeName << "|TarsSyncCallTimeoutException:" << tex.what() << endl); + result = tex.what(); + iRet = EM_TARS_CALL_NODE_TIMEOUT_ERR; + } + catch(TarsNodeNotRegistryException& rex) + { + current->setResponse(true); + iRet = EM_TARS_NODE_NOT_REGISTRY_ERR; + TLOGERROR("AdminRegistryImp::getPatchPercent: '" <<(application + "." + serverName + "_" + nodeName + " Caller:" + current->getIp() + ":" + TC_Common::tostr(current->getPort()) + + "' TarsNodeNotRegistryException:" + rex.what())<setResponse(true); + iRet = EM_TARS_UNKNOWN_ERR; + TLOGERROR("AdminRegistryImp::getPatchPercent: '" <<(application + "." + serverName + "_" + nodeName + " Caller:" + current->getIp() + ":" + TC_Common::tostr(current->getPort()) + + "' TarsException:" + ex.what())<loadServer(application, serverName, result); + } + catch(TarsSyncCallTimeoutException& tex) + { + TLOGERROR("AdminRegistryImp::loadServer: "<< application + "." + serverName + "_" + nodeName << "|Exception:" << tex.what() << endl); + return EM_TARS_CALL_NODE_TIMEOUT_ERR; + } + catch(TarsNodeNotRegistryException& rex) + { + TLOGERROR("AdminRegistryImp::loadServer: '"<<(" '" + application + "." + serverName + "_" + nodeName + + "' exception:" + rex.what())< server; + server = _db.getServers(application, serverName, nodeName, true); + if(server.size() > 0) + { + profileTemplate = server[0].profile; + iRet = 0; + } + } + TLOGDEBUG( "AdminRegistryImp::getServerProfileTemplate get " << application<<"."<getIp(); + return 0; +} + +int AdminRegistryImp::gridPatchServer(const vector &gridDescList, vector &gridFailDescList, std::string & resultDesc, tars::TarsCurrentPtr current) +{ + TLOGDEBUG(__FUNCTION__ << "|gridDescList size:" << gridDescList.size() << endl); + + int iRet = 0; + + try + { + gridFailDescList.clear(); + + for(size_t i = 0; i < gridDescList.size(); ++i) + { + if(gridDescList[i].application != "" && gridDescList[i].servername != "" && gridDescList[i].nodename != "") + { + string status(""); + + if(gridDescList[i].status == NORMAL) + { + status = "NORMAL"; + } + else if(gridDescList[i].status == GRID) + { + status = "GRID"; + } + else + { + status = "NO_FLOW"; + } + + int ret = _db.gridPatchServer(gridDescList[i].application, gridDescList[i].servername, gridDescList[i].nodename, status); + + if(ret < 0) + { + gridFailDescList.push_back(gridDescList[i]); + iRet = -1; + TLOGERROR(__FUNCTION__ << "|app:" << gridDescList[i].application << "|servername:" << gridDescList[i].servername << "|node:" << gridDescList[i].nodename << "|state:" << status << "|ret:" << ret << endl); + DLOG<<__FUNCTION__ << "|app:" << gridDescList[i].application << "|servername:" << gridDescList[i].servername << "|node:" << gridDescList[i].nodename << "|state:" << status << "|ret:" << ret << endl; + } + else + { + TLOGDEBUG(__FUNCTION__ << "|app:" << gridDescList[i].application << "|servername:" << gridDescList[i].servername << "|node:" << gridDescList[i].nodename << "|state:" << status << "|ret:" << ret << endl); + DLOG<<__FUNCTION__ << "|app:" << gridDescList[i].application << "|servername:" << gridDescList[i].servername << "|node:" << gridDescList[i].nodename << "|state:" << status << "|ret:" << ret << endl; + } + } + else + { + TLOGERROR(__FUNCTION__ << "|app:" << gridDescList[i].application << "|servername:" << gridDescList[i].servername << "|node:" << gridDescList[i].nodename << endl); + DLOG<<__FUNCTION__ << "|app:" << gridDescList[i].application << "|servername:" << gridDescList[i].servername << "|node:" << gridDescList[i].nodename << endl; + } + } + + return iRet; + } + catch(exception & ex) + { + iRet = EM_TARS_UNKNOWN_ERR; + resultDesc = string(__FUNCTION__) + "|exception:" + ex.what(); + TLOGERROR(resultDesc << endl); + DLOG<tars_timeout(_defaultTime); + + AdminReg::async_response_batchPatch(_current, ret, result); +} + +void PatchProCallbackImp::callback_patchPro_exception(tars::Int32 ret) +{ + int iRet = EM_TARS_UNKNOWN_ERR; + _nodePrx->tars_timeout(_defaultTime); + + if(ret == tars::TARSSERVERQUEUETIMEOUT || ret == tars::TARSASYNCCALLTIMEOUT) + { + iRet = EM_TARS_CALL_NODE_TIMEOUT_ERR; + } + + AdminReg::async_response_batchPatch(_current, iRet, ""); + TLOGDEBUG("PatchProCallbackImp::callback_patchPro_exception: |exception ret."<getIp() << ":" << _current->getPort() << "|" << ret <getIp() << ":" << _current->getPort() << "|" << ret <getIp() << ":" << _current->getPort() << "|" << ret <getIp() << ":" << _current->getPort() << "|" << ret <getIp() << ":" << _current->getPort() << "|" << ret << "|" << result <getIp() << ":" << _current->getPort() << "|" << ret <getState(_application, _serverName, resultRef); + _state.presentStateInNode = etos(stateInNode); + _state.processId = _nodePrx->getServerPid(_application, _serverName, resultRef); + TLOGWARN("GetServerStateCallbackImp::callback_getStateInfo_exception '" + _application + "." + _serverName + "_" + _nodeName<<"|"<< resultRef <getState(_application, _serverName, result); + _state.presentStateInNode = etos(stateInNode); + _state.processId = _nodePrx->getServerPid(_application, _serverName, result); + TLOGERROR("GetServerStateCallbackImp::callback_getStateInfo_exception '" + _application + "." + _serverName + "_" + _nodeName<<"|"<< result < + */ + virtual int getTaskHistory(const string & application, const string & serverName, const string & command, vector &taskRsp, tars::TarsCurrentPtr current); + + /** + * 设置任务状态 + * + * @param itemNo + * @param startTime + * @param endTime + * @param status + * @param log + * @param current + * + * @return int + */ + virtual int setTaskItemInfo(const string & itemNo, const map &info, tars::TarsCurrentPtr current); + + /***********application****************/ + /** + * 卸载服务 + * + * @param application + * @param serverName + * @param nodeName + * @param current + * + * @return int + */ + virtual int undeploy(const string & application, const string & serverName, const string & nodeName, const string &user, string &log, tars::TarsCurrentPtr current); + + /** + * 获取application列表 + * + * @param null + * @param out result : 结果描述 + * + * @return application列表 + */ + virtual vector getAllApplicationNames(string &result, tars::TarsCurrentPtr current); + + + /***********node****************/ + + /** + * 获取node列表 + * + * @param null + * @param out result : 结果描述 + * + * @return node 列表 + */ + virtual vector getAllNodeNames(string &result, tars::TarsCurrentPtr current); + + /** + * 获取node版本 + * @param name node名称 + * @param version node版本 + * @param out result 结果描述 + * @return 0-成功 others-失败 + */ + virtual int getNodeVesion(const string &nodeName, string &version, string & result, tars::TarsCurrentPtr current); + + /** + * ping node + * + * @param name: node id + * @param out result : 结果描述 + * + * @return : true-ping通;false-不通 + */ + virtual bool pingNode(const string & name, string &result, tars::TarsCurrentPtr current); + + /** + * 停止 node + * + * @param name: node id + * @param out result : 结果描述 + * + * @return : 0-成功 others-失败 + */ + virtual int shutdownNode(const string & name, string &result, tars::TarsCurrentPtr current); + + /** + * 获取server列表 + * + * @param name: null + * @param out result : 结果描述 + * + * @return: server列表及相关信息 + */ + virtual vector > getAllServerIds(string &result, tars::TarsCurrentPtr current); + + /** + * 获取特定server状态 + * + * @param application: 应用 + * @param serverName : server名 + * @param nodeNmae : node id + * @param out state : 状态 + * @param out result : 结果描述 + * + * @return : 处理结果 + */ + virtual int getServerState(const string & application, const string & serverName, const string & nodeName, ServerStateDesc &state, string &result, tars::TarsCurrentPtr current); + + /** + * 获取特定ip所属group + * + * @param sting: ip + * @param out int : group id + * @param out result : 结果描述 + * + * @return : 处理结果 + */ + + virtual int getGroupId(const string & ip,int &groupId, string &result, tars::TarsCurrentPtr current); + + /** + * 启动特定server + * + * @param application: 应用 + * @param serverName : server名 + * @param nodeName : node id + * @param out result : 结果描述 + * + * @return : 0-成功 others-失败 + */ + virtual int startServer(const string & application, const string & serverName, const string & nodeName, string &result, tars::TarsCurrentPtr current); + + /** + * 停止特定server + * + * @param application: 应用 + * @param serverName : server名 + * @param nodeName : node id + * @param out result : 结果描述 + * + * @return : 0-成功 others-失败 + */ + virtual int stopServer(const string & application, const string & serverName, const string & nodeName, string &result, tars::TarsCurrentPtr current); + + /** + * 重启特定server + * + * @param application: 应用 + * @param serverName : server名 + * @param nodeName : node id + * @param out result : 结果描述 + * + * @return : 0-成功 others-失败 + */ + virtual int restartServer(const string & application, const string & serverName, const string & nodeName, string &result, tars::TarsCurrentPtr current); + + /** + * 通知服务 + * @param application + * @param serverName + * @param nodeName + * @param command + * @param result + * @param current + * + * @return int + */ + virtual int notifyServer(const string & application, const string & serverName, const string & nodeName, const string &command, string &result, tars::TarsCurrentPtr current); + + /** + * 批量发布 + * + * @param PatchRequest : 发布请求 + * @param out result : 结果描述 + * + * @return : 0-成功 others-失败 + */ + virtual int batchPatch(const tars::PatchRequest & req, string &result, tars::TarsCurrentPtr current); + + /** + * 发布成功 + * + * @param req + * @param result + * @param current + * + * @return int + */ + virtual int updatePatchLog(const string &application, const string & serverName, const string & nodeName, const string & patchId, const string & user, const string &patchType, bool succ, tars::TarsCurrentPtr current); + + /** + * 获取服务发布进度 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @param nodeName :node id + * @out tPatchInfo :发布百分比 + * @return :0-成功 others-失败 + */ + virtual int getPatchPercent(const string &application, const string &serverName,const string & nodeName, PatchInfo &tPatchInfo, tars::TarsCurrentPtr current); + + /** + * 加载特定server + * + * @param application: 应用 + * @param serverName : server名 + * @param nodeName : node id + * @param out result : 结果描述 + * + * @return : 0-成功 others-失败 + */ + virtual int loadServer(const string & application, const string & serverName, const string & nodeName, string &result, tars::TarsCurrentPtr current); + + /** + * 获取相应模板 + * + * @param profileName: 模板名称 + * @param out profileTemplate: 模板内容 + * @param out resultDesc: 结果描述 + * + * @return : 0-成功 others-失败 + */ + virtual int getProfileTemplate(const std::string & profileName,std::string &profileTemplate, std::string & resultDesc, tars::TarsCurrentPtr current); + + /** + * 获取务服相应模板 + * + * @param application: 应用 + * @param serverName : server名 + * @param nodeName : node id + * @param out profileTemplate: 模板内容 + * @param out resultDesc: 结果描述 + * + * @return : 0-成功 others-失败 + */ + virtual int getServerProfileTemplate(const string & application, const string & serverName, const string & nodeName,std::string &profileTemplate, std::string & resultDesc, tars::TarsCurrentPtr current); + + /** + * node通过接口获取连接上主控的node ip + * @param sNodeIp: node 的ip + * + * @return 0-成功 others-失败 + */ + virtual int getClientIp(std::string &sClientIp,tars::TarsCurrentPtr current); + + virtual int gridPatchServer(const vector &gridDescList, vector &gridFailDescList, std::string & resultDesc, tars::TarsCurrentPtr current); +protected: + + //数据库操作类对象 + DbProxy _db; + + PatchPrx _patchPrx; +}; + +class PatchProCallbackImp: public NodePrxCallback +{ +public: + PatchProCallbackImp(const tars::PatchRequest& req, const NodePrx& nodePrx, int defaultTime, tars::TarsCurrentPtr current) + : _reqPro(req) + , _nodePrx(nodePrx) + , _defaultTime(defaultTime) + , _current(current) + { + } + + virtual void callback_patchPro(tars::Int32 ret, const std::string& result); + virtual void callback_patchPro_exception(tars::Int32 ret); + +private: + + tars::PatchRequest _reqPro; + NodePrx _nodePrx; + int _defaultTime; + tars::TarsCurrentPtr _current; +}; + + +class StartServerCallbackImp: public NodePrxCallback +{ +public: + StartServerCallbackImp(string application, string serverName, string nodeName, tars::TarsCurrentPtr current) + : _application(application) + , _serverName(serverName) + , _nodeName(nodeName) + , _current(current) + { + } + + virtual void callback_startServer(tars::Int32 ret, const std::string& result); + virtual void callback_startServer_exception(tars::Int32 ret); + +private: + string _application; + string _serverName; + string _nodeName; + tars::TarsCurrentPtr _current; +}; + +class StopServerCallbackImp: public NodePrxCallback +{ +public: + StopServerCallbackImp(string application, string serverName, string nodeName, tars::TarsCurrentPtr current) + : _application(application) + , _serverName(serverName) + , _nodeName(nodeName) + , _current(current) + { + } + + virtual void callback_stopServer(tars::Int32 ret, const std::string& result); + virtual void callback_stopServer_exception(tars::Int32 ret); + +private: + string _application; + string _serverName; + string _nodeName; + tars::TarsCurrentPtr _current; +}; + +class NotifyServerCallbackImp: public NodePrxCallback +{ +public: + NotifyServerCallbackImp(tars::TarsCurrentPtr current) + : _current(current) + { + } + + virtual void callback_notifyServer(tars::Int32 ret, const std::string& result); + virtual void callback_notifyServer_exception(tars::Int32 ret); + +private: + tars::TarsCurrentPtr _current; +}; + +class GetServerStateCallbackImp: public NodePrxCallback +{ +public: + GetServerStateCallbackImp(const NodePrx& nodePrx, string application, string serverName, string nodeName, const ServerStateDesc& state, tars::TarsCurrentPtr current) + : _nodePrx(nodePrx) + , _application(application) + , _serverName(serverName) + , _nodeName(nodeName) + , _state(state) + , _current(current) + { + } + + virtual void callback_getStateInfo(tars::Int32 ret, const tars::ServerStateInfo& info, const std::string& result); + virtual void callback_getStateInfo_exception(tars::Int32 ret); +private: + NodePrx _nodePrx; + string _application; + string _serverName; + string _nodeName; + ServerStateDesc _state; + tars::TarsCurrentPtr _current; +}; + + +class GetPatchPercentCallbackImp: public NodePrxCallback +{ +public: + GetPatchPercentCallbackImp(string application, string serverName, string nodeName, tars::TarsCurrentPtr current) + : _application(application) + , _serverName(serverName) + , _nodeName(nodeName) + , _current(current) + { + } + + virtual void callback_getPatchPercent(tars::Int32 ret, const tars::PatchInfo& tPatchInfo); + virtual void callback_getPatchPercent_exception(tars::Int32 ret); + +private: + string _application; + string _serverName; + string _nodeName; + tars::TarsCurrentPtr _current; +}; + + +#endif diff --git a/AdminRegistryServer/AdminRegistryServer.cpp b/AdminRegistryServer/AdminRegistryServer.cpp new file mode 100644 index 00000000..6a1a5153 --- /dev/null +++ b/AdminRegistryServer/AdminRegistryServer.cpp @@ -0,0 +1,106 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "AdminRegistryServer.h" +#include "AdminRegistryImp.h" + +TC_Config * g_pconf; +AdminRegistryServer g_app; + +extern TC_Config * g_pconf; + +//内部版本 +const string SERVER_VERSION = "B002"; + +void AdminRegistryServer::initialize() +{ + TLOGDEBUG("AdminRegistryServer::initialize..." << endl); + + try + { + string size = Application::getCommunicator()->getProperty("timeout-queue-size", ""); + if(size.empty()) + { + Application::getCommunicator()->setProperty("timeout-queue-size","100"); + } + + loadServantEndpoint(); + + //轮询线程 + _reapThread.init(); + _reapThread.start(); + + //供admin client访问的对象 + string adminObj = g_pconf->get("/tars/objname", ""); + if(adminObj != "") + { + addServant(adminObj); + } + } + catch(TC_Exception & ex) + { + TLOGERROR("RegistryServer initialize exception:" << ex.what() << endl); + cerr << "RegistryServer initialize exception:" << ex.what() << endl; + exit(-1); + } + + TLOGDEBUG("RegistryServer::initialize OK!" << endl); +} + +int AdminRegistryServer::loadServantEndpoint() +{ + map mapAdapterServant; + mapAdapterServant = ServantHelperManager::getInstance()->getAdapterServant(); + + map::iterator iter; + for(iter = mapAdapterServant.begin(); iter != mapAdapterServant.end(); iter++ ) + { + TC_Endpoint ep = getEpollServer()->getBindAdapter(iter->first)->getEndpoint(); + + _mapServantEndpoint[iter->second] = ep.toString(); + + TLOGDEBUG("registry obj: " << iter->second << " = " << ep.toString() < getServantEndpoint() { return _mapServantEndpoint; } + +private: + int loadServantEndpoint(); + +protected: + + //用于执行定时操作的线程对象 + AdminReapThread _reapThread; + + //对象-适配器 列表 + map _mapServantEndpoint; +}; + +extern AdminRegistryServer g_app; +extern const string SERVER_VERSION; diff --git a/AdminRegistryServer/CMakeLists.txt b/AdminRegistryServer/CMakeLists.txt new file mode 100644 index 00000000..ed28f9d6 --- /dev/null +++ b/AdminRegistryServer/CMakeLists.txt @@ -0,0 +1,6 @@ +set(MODULE "tarsAdminRegistry") + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/deploy/${MODULE}/bin) + +#complice_module(${MODULE} "AdminReg.tars") +complice_module(${MODULE}) diff --git a/AdminRegistryServer/DbProxy.cpp b/AdminRegistryServer/DbProxy.cpp new file mode 100644 index 00000000..9a235598 --- /dev/null +++ b/AdminRegistryServer/DbProxy.cpp @@ -0,0 +1,953 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "DbProxy.h" +#include "AdminRegistryServer.h" +#include "util/tc_parsepara.h" +#include "ExecuteTask.h" + +TC_ThreadLock DbProxy::_mutex; + +map DbProxy::_mapNodePrxCache; + +TC_ThreadLock DbProxy::_NodePrxLock; +vector >DbProxy::_serverGroupRule; +//key-ip, value-组编号 +map DbProxy::_serverGroupCache; + + +int DbProxy::init(TC_Config *pconf) +{ + try + { + + TC_DBConf tcDBConf; + tcDBConf.loadFromMap(pconf->getDomainMap("/tars/db")); + _mysqlReg.init(tcDBConf); + } + catch (TC_Config_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " exception: " << ex.what() << endl); + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " exception: " << ex.what() << endl); + } + + return 0; +} + +int DbProxy::addTaskReq(const TaskReq &taskReq) +{ + try + { + for (size_t i = 0; i < taskReq.taskItemReq.size(); i++) + { + map > data; + data["task_no"] = make_pair(TC_Mysql::DB_STR, taskReq.taskNo); + data["item_no"] = make_pair(TC_Mysql::DB_STR, taskReq.taskItemReq[i].itemNo); + data["application"] = make_pair(TC_Mysql::DB_STR, taskReq.taskItemReq[i].application); + data["server_name"] = make_pair(TC_Mysql::DB_STR, taskReq.taskItemReq[i].serverName); + data["node_name"] = make_pair(TC_Mysql::DB_STR, taskReq.taskItemReq[i].nodeName); + data["command"] = make_pair(TC_Mysql::DB_STR, taskReq.taskItemReq[i].command); + data["parameters"] = make_pair(TC_Mysql::DB_STR, TC_Parsepara(taskReq.taskItemReq[i].parameters).tostr()); + + _mysqlReg.insertRecord("t_task_item", data); + } + + { + map > data; + data["task_no"] = make_pair(TC_Mysql::DB_STR, taskReq.taskNo); + data["serial"] = make_pair(TC_Mysql::DB_INT, TC_Common::tostr(taskReq.serial)); + data["create_time"] = make_pair(TC_Mysql::DB_INT, "now()"); + data["user_name"] = make_pair(TC_Mysql::DB_STR, taskReq.userName); + + _mysqlReg.insertRecord("t_task", data); + } + } + catch (exception &ex) + { + TLOGERROR("DbProxy::addTaskReq exception: " << ex.what() << endl); + return -1; + } + + return 0; +} + +int DbProxy::getTaskRsp(const string &taskNo, TaskRsp &taskRsp) +{ + + try + { + string sql = "select * from t_task as t1, t_task_item as t2 where t1.task_no=t2.task_no and t2.task_no='" + + _mysqlReg.escapeString(taskNo) + "'"; + + tars::TC_Mysql::MysqlData item = _mysqlReg.queryRecord(sql); + if (item.size() == 0) + { + TLOGERROR("DbProxy::getTaskRsp 't_task' not task: " << taskNo << endl); + return -1; + } + + taskRsp.taskNo = item[0]["task_no"]; + taskRsp.serial = TC_Common::strto(item[0]["serial"]); + taskRsp.userName = item[0]["user_name"]; + + + for (unsigned i = 0; i < item.size(); i++) + { + TaskItemRsp rsp; + rsp.startTime = item[i]["start_time"]; + rsp.endTime = item[i]["end_time"]; + rsp.status = (EMTaskItemStatus)TC_Common::strto(item[i]["status"]); + rsp.statusInfo = etos(rsp.status); + + rsp.req.taskNo = item[i]["task_no"]; + rsp.req.itemNo = item[i]["item_no"]; + rsp.req.application = item[i]["application"]; + rsp.req.serverName = item[i]["server_name"]; + rsp.req.nodeName = item[i]["node_name"]; + rsp.req.setName = item[i]["set_name"]; + rsp.req.command = item[i]["command"]; + rsp.req.parameters = TC_Parsepara(item[i]["parameters"]).toMap(); + + taskRsp.taskItemRsp.push_back(rsp); + } + + ExecuteTask::getInstance()->checkTaskRspStatus(taskRsp); + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("DbProxy::getTaskRsp exception"< &taskRsp) +{ + string sql = "select t1.`create_time`, t1.`serial`, t1.`user_name`, t2.* from t_task as t1, t_task_item as t2 where t1.task_no=t2.task_no and t2.application='" + + _mysqlReg.escapeString(application) + "' and t2.server_name='" + + _mysqlReg.escapeString(serverName) + "' and t2.command='" + + _mysqlReg.escapeString(command) + "' order by create_time desc, task_no"; + + try + { + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sql); + TLOGDEBUG("DbProxy::getTaskHistory size:" << res.size() << ", sql:" << sql << endl); + for (unsigned i = 0; i < res.size(); i++) + { + string taskNo = res[i]["task_no"]; + + //获取Item + TaskItemRsp itemRsp; + itemRsp.startTime = res[i]["start_time"]; + itemRsp.endTime = res[i]["end_time"]; + itemRsp.status = (EMTaskItemStatus)TC_Common::strto(res[i]["status"]); + itemRsp.statusInfo= etos(itemRsp.status); + + itemRsp.req.taskNo = res[i]["task_no"]; + itemRsp.req.itemNo = res[i]["item_no"]; + itemRsp.req.application = res[i]["application"]; + itemRsp.req.serverName = res[i]["server_name"]; + itemRsp.req.nodeName = res[i]["node_name"]; + itemRsp.req.setName = res[i]["set_name"]; + itemRsp.req.command = res[i]["command"]; + itemRsp.req.parameters = TC_Parsepara(res[i]["parameters"]).toMap(); + + if (taskRsp.empty() || taskRsp[taskRsp.size() - 1].taskNo != taskNo) + { + //新的TaskRsp + TaskRsp rsp; + rsp.taskNo = res[i]["task_no"]; + rsp.serial = TC_Common::strto(res[i]["serial"]); + rsp.userName = res[i]["user_name"]; + + rsp.taskItemRsp.push_back(itemRsp); + + taskRsp.push_back(rsp); + } + else + { + taskRsp.back().taskItemRsp.push_back(itemRsp); + } + } + } + catch (exception &ex) + { + TLOGERROR("DbProxy::getTaskHistory exception: " << ex.what() << endl); + return -1; + } + + return 0; +} + +int DbProxy::setTaskItemInfo(const string & itemNo, const map &info) +{ + string where = " where item_no='" + itemNo + "'"; + try + { + map > data; + data["item_no"] = make_pair(TC_Mysql::DB_STR, itemNo); + map::const_iterator it = info.find("start_time"); + if (it != info.end()) + { + data["start_time"] = make_pair(TC_Mysql::DB_STR, it->second); + } + it = info.find("end_time"); + if (it != info.end()) + { + data["end_time"] = make_pair(TC_Mysql::DB_STR, it->second); + } + it = info.find("status"); + if (it != info.end()) + { + data["status"] = make_pair(TC_Mysql::DB_INT, it->second); + } + it = info.find("log"); + if (it != info.end()) + { + data["log"] = make_pair(TC_Mysql::DB_STR, it->second); + } + + _mysqlReg.updateRecord("t_task_item", data, where); + } + catch (exception &ex) + { + TLOGERROR("DbProxy::setTaskItemInfo exception: " << ex.what() << endl); + return -1; + } + + return 0; +} + +int DbProxy::undeploy(const string & application, const string & serverName, const string & nodeName, const string &user, string &log) +{ + string where = "where application='" + application + "' and server_name='" + serverName + "' and node_name='" +nodeName + "'"; + + try + { + + _mysqlReg.deleteRecord("t_server_conf", where); + + _mysqlReg.deleteRecord("t_adapter_conf", where); + + } + catch (exception &ex) + { + log = ex.what(); + TLOGERROR("DbProxy::undeploy exception: " << ex.what() << endl); + return -1; + } + + return 0; +} + +map DbProxy::getActiveNodeList(string& result) +{ + map mapNodeList; + try + { + string sql = + "select node_name, node_obj from t_node_info " + "where present_state='active'"; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sql); + TLOGDEBUG("DbProxy::getActiveNodeList (present_state='active') affected:" << res.size() << endl); + for (unsigned i = 0; i < res.size(); i++) + { + mapNodeList[res[i]["node_name"]] = res[i]["node_obj"]; + } + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("DbProxy::getActiveNodeList exception: " < 0) + { + version = res[0]["tars_version"]; + return 0; + + } + result = "node_name(" + nodeName + ") int table t_node_info not exist"; + } + catch (TC_Mysql_Exception& ex) + { + result = string(__FUNCTION__) + " exception: " + ex.what(); + TLOGERROR(result << endl); + } + return -1; +} + +int DbProxy::updateServerState(const string& app, const string& serverName, const string& nodeName, + const string& stateFields, tars::ServerState state, int processId) +{ + try + { + int64_t iStart = TC_TimeProvider::getInstance()->getNowMs(); + if (stateFields != "setting_state" && stateFields != "present_state") + { + TLOGDEBUG(app << "." << serverName << "_" << nodeName + << " not supported fields:" << stateFields << endl); + return -1; + } + + string sProcessIdSql = (stateFields == "present_state" ? + (", process_id = " + TC_Common::tostr(processId) + " ") : ""); + + string sql = + "update t_server_conf " + "set " + stateFields + " = '" + etos(state) + "' " + sProcessIdSql + + "where application='" + _mysqlReg.escapeString(app) + "' " + " and server_name='" + _mysqlReg.escapeString(serverName) + "' " + " and node_name='" + _mysqlReg.escapeString(nodeName) + "' "; + + _mysqlReg.execute(sql); + TLOGDEBUG(__FUNCTION__ << " " << app << "." << serverName << "_" << nodeName + << " affected:" << _mysqlReg.getAffectedRows() + << "|cost:" << (TC_TimeProvider::getInstance()->getNowMs() - iStart) << endl); + return 0; + + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " " << app << "." << serverName << "_" << nodeName + << " exception: " << ex.what() << endl); + return -1; + } +} + +int DbProxy::gridPatchServer(const string& app, const string& servername, const string& nodename, const string& status) +{ + try + { + string sql("update t_server_conf"); + sql += " set grid_flag='"; + sql += status; + sql += "' where application='"; + sql += _mysqlReg.escapeString(app); + sql += "' and server_name='"; + sql += _mysqlReg.escapeString(servername); + sql += "' and node_name='"; + sql += _mysqlReg.escapeString(nodename); + sql += "'"; + + int64_t iStart = TC_TimeProvider::getInstance()->getNowMs(); + + _mysqlReg.execute(sql); + + TLOGDEBUG(__FUNCTION__ << "|app:" << app << "|server:" << servername << "|node:" << nodename + << "|affected:" << _mysqlReg.getAffectedRows() << "|cost:" << (TC_TimeProvider::getInstance()->getNowMs() - iStart) << endl); + + return 0; + + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR(__FUNCTION__ << "|app:" << app << "|server:" << servername << "|node:" << nodename + << "|exception: " << ex.what() << endl); + return -1; + } +} + +vector DbProxy::getServers(const string& app, const string& serverName, const string& nodeName, bool withDnsServer) +{ + string sql; + vector vServers; + unsigned num = 0; + int64_t iStart = TC_TimeProvider::getInstance()->getNowMs(); + + try + { + //server详细配置 + string sCondition; + sCondition += "server.node_name='" + _mysqlReg.escapeString(nodeName) + "'"; + if (app != "") sCondition += " and server.application='" + _mysqlReg.escapeString(app) + "' "; + if (serverName != "") sCondition += " and server.server_name='" + _mysqlReg.escapeString(serverName) + "' "; + if (withDnsServer == false) sCondition += " and server.server_type !='tars_dns' "; //不获取dns服务 + +// " allow_ip, max_connections, servant, queuecap, queuetimeout,protocol,handlegroup,shmkey,shmcap," + + sql = + "select server.application, server.server_name, server.node_name, base_path, " + " exe_path, setting_state, present_state, adapter_name, thread_num, async_thread_num, endpoint," + " profile,template_name, " + " allow_ip, max_connections, servant, queuecap, queuetimeout,protocol,handlegroup," + " patch_version, patch_time, patch_user, " + " server_type, start_script_path, stop_script_path, monitor_script_path,config_center_port ," + " enable_set, set_name, set_area, set_group " + "from t_server_conf as server " + " left join t_adapter_conf as adapter using(application, server_name, node_name) " + "where " + sCondition; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sql); + num = res.size(); + //对应server在vector的下标 + map mapAppServerTemp; + + //获取模版profile内容 + map mapProfile; + + //分拆数据到server的信息结构里 + for (unsigned i = 0; i < res.size(); i++) + { + string sServerId = res[i]["application"] + "." + res[i]["server_name"] + + "_" + res[i]["node_name"]; + + if (mapAppServerTemp.find(sServerId) == mapAppServerTemp.end()) + { + //server配置 + ServerDescriptor server; + server.application = res[i]["application"]; + server.serverName = res[i]["server_name"]; + server.nodeName = res[i]["node_name"]; + server.basePath = res[i]["base_path"]; + server.exePath = res[i]["exe_path"]; + server.settingState = res[i]["setting_state"]; + server.presentState = res[i]["present_state"]; + server.patchVersion = res[i]["patch_version"]; + server.patchTime = res[i]["patch_time"]; + server.patchUser = res[i]["patch_user"]; + server.profile = res[i]["profile"]; + server.serverType = res[i]["server_type"]; + server.startScript = res[i]["start_script_path"]; + server.stopScript = res[i]["stop_script_path"]; + server.monitorScript = res[i]["monitor_script_path"]; + server.configCenterPort = TC_Common::strto(res[i]["config_center_port"]); + + server.setId = ""; + if (TC_Common::lower(res[i]["enable_set"]) == "y") + { + server.setId = res[i]["set_name"] + "." + res[i]["set_area"] + "." + res[i]["set_group"]; + } + + //获取父模版profile内容 + if (mapProfile.find(res[i]["template_name"]) == mapProfile.end()) + { + string sResult; + mapProfile[res[i]["template_name"]] = getProfileTemplate(res[i]["template_name"], sResult); + } + + TC_Config tParent, tProfile; + tParent.parseString(mapProfile[res[i]["template_name"]]); + tProfile.parseString(server.profile); + int iDefaultAsyncThreadNum = 3; + if (server.serverType == "tars_nodejs") + { + iDefaultAsyncThreadNum = 0; + } + int iConfigAsyncThreadNum = TC_Common::strto(TC_Common::trim(res[i]["async_thread_num"])); + iDefaultAsyncThreadNum = iConfigAsyncThreadNum > iDefaultAsyncThreadNum ? iConfigAsyncThreadNum : iDefaultAsyncThreadNum; + server.asyncThreadNum = TC_Common::strto(tProfile.get("/tars/application/client", TC_Common::tostr(iDefaultAsyncThreadNum))); + tParent.joinConfig(tProfile, true); + server.profile = tParent.tostr(); + + mapAppServerTemp[sServerId] = vServers.size(); + vServers.push_back(server); + } + + //adapter配置 + AdapterDescriptor adapter; + adapter.adapterName = res[i]["adapter_name"]; + if (adapter.adapterName == "") + { + //adapter没配置,left join 后为 NULL,不放到adapters map + continue; + } + + adapter.threadNum = res[i]["thread_num"]; + adapter.endpoint = res[i]["endpoint"]; + adapter.maxConnections = TC_Common::strto(res[i]["max_connections"]); + adapter.allowIp = res[i]["allow_ip"]; + adapter.servant = res[i]["servant"]; + adapter.queuecap = TC_Common::strto(res[i]["queuecap"]); + adapter.queuetimeout = TC_Common::strto(res[i]["queuetimeout"]); + adapter.protocol = res[i]["protocol"]; + adapter.handlegroup = res[i]["handlegroup"]; + + vServers[mapAppServerTemp[sServerId]].adapters[adapter.adapterName] = adapter; + } + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " " << app << "." << serverName << "_" << nodeName + << " exception: " << ex.what() << "|" << sql << endl); + return vServers; + } + catch (TC_Config_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " " << app << "." << serverName << "_" << nodeName + << " TC_Config_Exception exception: " << ex.what() << endl); + throw TarsException(string("TC_Config_Exception exception: ") + ex.what()); + } + + TLOGDEBUG(app << "." << serverName << "_" << nodeName + << " getServers affected:" << num + << "|cost:" << (TC_TimeProvider::getInstance()->getNowMs() - iStart) << endl); + + return vServers; + +} + +int DbProxy::getNodeList(const string& app, const string& serverName, vector& nodeNames) +{ + int ret = 0; + nodeNames.clear(); + try + { + string sql = "select node_name from t_server_conf where application='" + _mysqlReg.escapeString(app) + "' and server_name='" + _mysqlReg.escapeString(serverName) + "'"; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sql); + + for (unsigned i = 0; i < res.size(); i++) + { + nodeNames.push_back(res[i]["node_name"]); + } + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " exception: " << ex.what() << endl); + ret = -1; + } + return ret; +} + + +string DbProxy::getProfileTemplate(const string& sTemplateName, string& sResultDesc) +{ + map mapRecursion; + return getProfileTemplate(sTemplateName, mapRecursion, sResultDesc); +} + +string DbProxy::getProfileTemplate(const string& sTemplateName, map& mapRecursion, string& sResultDesc) +{ + try + { + string sql = "select template_name, parents_name, profile from t_profile_template " + "where template_name='" + _mysqlReg.escapeString(sTemplateName) + "'"; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sql); + + if (res.size() == 0) + { + sResultDesc += "(" + sTemplateName + ":template not found)"; + return ""; + } + + TC_Config confMyself, confParents; + confMyself.parseString(res[0]["profile"]); + //mapRecursion用于避免重复继承 + mapRecursion[res[0]["template_name"]] = 1; + + if (res[0]["parents_name"] != "" && mapRecursion.find(res[0]["parents_name"]) == mapRecursion.end()) + { + confParents.parseString(getProfileTemplate(res[0]["parents_name"], mapRecursion, sResultDesc)); + confMyself.joinConfig(confParents, false); + } + sResultDesc += "(" + sTemplateName + ":OK)"; + + TLOGDEBUG(__FUNCTION__ << " " << sTemplateName << " " << sResultDesc << endl); + + return confMyself.tostr(); + } + catch (TC_Mysql_Exception& ex) + { + sResultDesc += "(" + sTemplateName + ":" + ex.what() + ")"; + TLOGERROR(__FUNCTION__ << " exception: " << ex.what() << endl); + } + catch (TC_Config_Exception& ex) + { + sResultDesc += "(" + sTemplateName + ":" + ex.what() + ")"; + TLOGERROR(__FUNCTION__ << " TC_Config_Exception exception: " << ex.what() << endl); + } + + return ""; +} + +vector DbProxy::getAllApplicationNames(string& result) +{ + vector vApps; + try + { + string sql = "select distinct application from t_server_conf"; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sql); + TLOGDEBUG(__FUNCTION__ << " affected:" << res.size() << endl); + + for (unsigned i = 0; i < res.size(); i++) + { + vApps.push_back(res[i]["application"]); + } + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " exception: " << ex.what() << endl); + return vApps; + } + + return vApps; + +} + +vector > DbProxy::getAllServerIds(string& result) +{ + vector > vServers; + try + { + string sql = + "select application, server_name, node_name, setting_state, present_state,server_type from t_server_conf"; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sql); + TLOGDEBUG(__FUNCTION__ << " affected:" << res.size() << endl); + + for (unsigned i = 0; i < res.size(); i++) + { + vector server; + server.push_back(res[i]["application"] + "." + res[i]["server_name"] + "_" + res[i]["node_name"]); + server.push_back(res[i]["setting_state"]); + server.push_back(res[i]["present_state"]); + server.push_back(res[i]["server_type"]); + vServers.push_back(server); + } + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " exception: " << ex.what() << endl); + return vServers; + } + + return vServers; + +} +int DbProxy::getGroupId(const string& ip) +{ + bool bFind = false; + int iGroupId = -1; + string sOrder; + string sAllowIpRule; + string sDennyIpRule; + vector > vServerGroupInfo; + try + { + { + TC_ThreadLock::Lock lock(_mutex); + map::iterator it = _serverGroupCache.find(ip); + if (it != _serverGroupCache.end()) + { + return it->second; + } + vServerGroupInfo = _serverGroupRule; + } + + for (unsigned i = 0; i < vServerGroupInfo.size(); i++) + { + iGroupId = TC_Common::strto(vServerGroupInfo[i]["group_id"]); + sOrder = vServerGroupInfo[i]["ip_order"]; + sAllowIpRule = vServerGroupInfo[i]["allow_ip_rule"]; + sDennyIpRule = vServerGroupInfo[i]["denny_ip_rule"]; + vector vAllowIp = TC_Common::sepstr(sAllowIpRule, ",|;"); + vector vDennyIp = TC_Common::sepstr(sDennyIpRule, ",|;"); + if (sOrder == "allow_denny") + { + if (TC_Common::matchPeriod(ip, vAllowIp)) + { + bFind = true; + break; + } + } + else if (sOrder == "denny_allow") + { + if (TC_Common::matchPeriod(ip, vDennyIp)) + { + //在不允许的ip列表中则不属于本行所对应组 继续匹配查找 + continue; + } + if (TC_Common::matchPeriod(ip, vAllowIp)) + { + bFind = true; + break; + } + } + } + + if (bFind == true) + { + TC_ThreadLock::Lock lock(_mutex); + _serverGroupCache[ip] = iGroupId; + + TLOGINFO("get groupId succ|ip|" << ip + << "|group_id|" << iGroupId << "|ip_order|" << sOrder + << "|allow_ip_rule|" << sAllowIpRule + << "|denny_ip_rule|" << sDennyIpRule + << "|ServerGroupCache|" << TC_Common::tostr(_serverGroupCache) << endl); + + return iGroupId; + } + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " exception: " << ex.what() << endl); + } + catch (exception& ex) + { + TLOGERROR(__FUNCTION__ << " " << ex.what() << endl); + } + return -1; +} + +NodePrx DbProxy::getNodePrx(const string& nodeName) +{ + try + { + TC_ThreadLock::Lock lock(_NodePrxLock); + + if (_mapNodePrxCache.find(nodeName) != _mapNodePrxCache.end()) + { + return _mapNodePrxCache[nodeName]; + } + + string sql = + "select node_obj " + "from t_node_info " + "where node_name='" + _mysqlReg.escapeString(nodeName) + "' and present_state='active'"; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sql); + TLOGDEBUG(__FUNCTION__ << " '" << nodeName << "' affected:" << res.size() << endl); + + if (res.size() == 0) + { + throw TarsNodeNotRegistryException("node '" + nodeName + "' not registered or heartbeart timeout,please check for it"); + } + + NodePrx nodePrx; + g_app.getCommunicator()->stringToProxy(res[0]["node_obj"], nodePrx); + + _mapNodePrxCache[nodeName] = nodePrx; + + return nodePrx; + + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " " << nodeName << " exception: " << ex.what() << endl); + throw TarsNodeNotRegistryException(string("get node record from db error:") + ex.what()); + } + catch (tars::TarsException& ex) + { + TLOGERROR(__FUNCTION__ << " " << nodeName << " exception: " << ex.what() << endl); + throw ex; + } + +} + +int DbProxy::checkRegistryTimeout(unsigned uTimeout) +{ + try + { + string sql = + "update t_registry_info " + "set present_state='inactive' " + "where last_heartbeat < date_sub(now(), INTERVAL " + tars::TC_Common::tostr(uTimeout) + " SECOND)"; + + _mysqlReg.execute(sql); + TLOGDEBUG(__FUNCTION__ << " (" << uTimeout << "s) affected:" << _mysqlReg.getAffectedRows() << endl); + + return _mysqlReg.getAffectedRows(); + + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " exception: " << ex.what() << endl); + return -1; + } + +} + +int DbProxy::updateRegistryInfo2Db(bool bRegHeartbeatOff) +{ + if (bRegHeartbeatOff) + { + TLOGDEBUG("updateRegistryInfo2Db not need to update reigstry status !" << endl); + return 0; + } + + map::iterator iter; + map mapServantEndpoint = g_app.getServantEndpoint(); + if (mapServantEndpoint.size() == 0) + { + TLOGERROR("fatal error, get registry servant failed!" << endl); + return -1; + } + + try + { + string sql = "replace into t_registry_info (locator_id, servant, endpoint, last_heartbeat, present_state, tars_version) " + "values "; + + string sVersion = TARS_VERSION; + sVersion += "_"; + sVersion += SERVER_VERSION; + + for (iter = mapServantEndpoint.begin(); iter != mapServantEndpoint.end(); iter++) + { + TC_Endpoint locator; + locator.parse(iter->second); + + sql += (iter == mapServantEndpoint.begin() ? string("") : string(", ")) + + "('" + locator.getHost() + ":" + TC_Common::tostr(locator.getPort()) + "', " + "'" + iter->first + "', '" + iter->second + "', now(), 'active', " + + "'" + _mysqlReg.escapeString(sVersion) + "')"; + } + + _mysqlReg.execute(sql); + TLOGDEBUG(__FUNCTION__ << " affected:" << _mysqlReg.getAffectedRows() << endl); + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " exception: " << ex.what() << endl); + return -1; + } + catch (exception& ex) + { + TLOGERROR(__FUNCTION__ << " exception: " << ex.what() << endl); + return -1; + } + + return 0; +} + +int DbProxy::loadIPPhysicalGroupInfo() +{ + try + { + string sql = "select group_id,ip_order,allow_ip_rule,denny_ip_rule,group_name from t_server_group_rule " + "order by group_id"; + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sql); + TLOGDEBUG(__FUNCTION__ << " get server group from db, records affected:" << res.size() << endl); + + + TC_ThreadLock::Lock lock(_mutex); + _serverGroupRule.clear(); + _serverGroupRule = res.data(); + + _serverGroupCache.clear(); //规则改变 清除以前缓存 + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " exception: " << ex.what() << endl); + } + catch (exception& ex) + { + TLOGERROR(__FUNCTION__ << " " << ex.what() << endl); + } + return -1; +} + +int DbProxy::getInfoByPatchId(const string &patchId, string &patchFile, string &md5) +{ + try + { + string sql = "select tgz, md5 from t_server_patchs where id=" + patchId; + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sql); + + if (res.size() == 0) + { + TLOGERROR(__FUNCTION__ << " get patch tgz, md5 from db error, no records! patchId=" << patchId << endl); + return -1; + } + + patchFile = res[0]["tgz"]; + md5 = res[0]["md5"]; + + return 0; + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " exception: " << ex.what() << endl); + } + catch (exception& ex) + { + TLOGERROR(__FUNCTION__ << " " << ex.what() << endl); + } + return -1; +} + +int DbProxy::updatePatchByPatchId(const string &application, const string & serverName, const string & nodeName, const string & patchId, const string & user, const string &patchType, bool succ) +{ + try + { + string sql = "update t_server_patchs set publish='1',publish_user='" + user + + "',publish_time=now(),lastuser='"+ user +"' where id=" + patchId; + + _mysqlReg.execute(sql); + + return 0; + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR(__FUNCTION__ << " exception: " << ex.what() << endl); + } + catch (exception& ex) + { + TLOGERROR(__FUNCTION__ << " " << ex.what() << endl); + } + return -1; +} + diff --git a/AdminRegistryServer/DbProxy.h b/AdminRegistryServer/DbProxy.h new file mode 100644 index 00000000..b4e0c8e0 --- /dev/null +++ b/AdminRegistryServer/DbProxy.h @@ -0,0 +1,289 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __DB_PROXY_H__ +#define __DB_PROXY_H__ + +#include "util/tc_common.h" +#include "util/tc_config.h" +#include "util/tc_monitor.h" +#include "util/tc_mysql.h" +#include "util/tc_file.h" +#include "Node.h" +#include "servant/TarsLogger.h" +#include "AdminReg.h" + +using namespace tars; +/** + * 主控获取node信息异常 + */ +struct TarsNodeNotRegistryException : public TarsException +{ + TarsNodeNotRegistryException(const string &buffer) : TarsException(buffer){}; + TarsNodeNotRegistryException(const string &buffer, int err) : TarsException(buffer, err){}; + ~TarsNodeNotRegistryException() throw(){}; +}; + +/** + * 数据库操作类 + */ +class DbProxy +{ +public: + /** + * 构造函数 + */ + DbProxy(){} + + /** + * 初始化 + * @param pconf 配置文件 + * @return 0-成功 others-失败 + */ + int init(TC_Config *pconf); + + /** + * 获取特定node id的对象代理 + * @param nodeName : node id + * @return : 对象代理的智能指针 + */ + NodePrx getNodePrx(const string & nodeName); + + /** + * 增加异步任务 + * + * @param taskNo + * @param taskReq + * @param serial + * + * @return string + */ + int addTaskReq(const TaskReq &taskReq); + + /** + * 获取 + * + * @param taskNo + * + * @return TaskRsp + */ + int getTaskRsp(const string &taskNo, TaskRsp &taskRsp); + + /** + * 获取历史的Task信息 + * + * @param application + * @param serverName + * @param command + * + * @return vector + */ + int getTaskHistory(const string & application, const string & serverName, const string & command, vector &taskRsp); + + /** + * 设置task item信息 + * + * @param itemNo + * @param startTime + * @param endTime + * @param status + * @param log + * @param current + * + * @return int + */ + int setTaskItemInfo(const string & itemNo, const map &info); + + /** + * 下线服务 + * + * @param application + * @param serverName + * @param nodeName + * + * @return int + */ + int undeploy(const string & application, const string & serverName, const string & nodeName, const string &user, string &log); + + /** + * 获取活动node列表endpoint信息 + * @param out result 结果描述 + * @return map : 对应id node的obj + */ + map getActiveNodeList(string & result); + + /** + * 获取node版本 + * @param name node名称 + * @param version node版本 + * @param out result 结果描述 + * @return 0-成功 others-失败 + */ + int getNodeVersion(const string &nodeName, string &version, string & result); + + /** + * 获取在该node部署的server列表 + * + * @param app: 应用 + * @param serverName: server 名 + * @param nodeName : node id + * + * @return server信息列表 + */ + vector getServers(const string & app, const string & serverName, const string & nodeName,bool withDnsServer = false); + + /** + * 根据应用和服务名,获取部署的node列表 + */ + int getNodeList(const string & app, const string & serverName, vector& nodeNames); + + /** + * 获取server的配置模板 + * @param sTemplateName 模板名称 + * @param sResultDesc 结果描述 + * @return 模板内容 + */ + string getProfileTemplate(const string & sTemplateName, string & sResultDesc); + + /** + * 根据patchId获取patch tgz包 + * + * @param patchId + * + * @return string + */ + int getInfoByPatchId(const string &patchId, string &patchFile, string &md5); + + /** + * 更新发布成功信息 + * + * @param patchId + * + * @return int + */ + int updatePatchByPatchId(const string &application, const string & serverName, const string & nodeName, const string & patchId, const string & user, const string &patchType, bool succ); + +protected: + /** + * 获取server的配置模板 + * @param sTemplateName 模板名称 + * @param mapRecursion 被递归到的模板 + * @param sResultDesc 结果描述 + * @return 模板内容 + */ + string getProfileTemplate(const string & sTemplateName, map & mapRecursion, string & sResultDesc); + +public: + /** + * 更新server状态 + * + * @param app: 应用 + * @param serverName: server 名 + * @param nodeName : node id + * @param stateFields: 更新状态字段名 + * @param state : server状态 + * + * @return server信息列表 + */ + int updateServerState(const string & app, const string & serverName, const string & nodeName, + const string & stateFields, tars::ServerState state, int processId = -1); + + + /** + * 获取application列表 + * @param null + * @param out reuslt + * @return application列表 + */ + vector getAllApplicationNames(string & result); + + + /** + * 获取server列表 + * @param null + * @return node 列表 + */ + vector > getAllServerIds(string & result); + + + /** + * 设置server发布版本 + * @param app: 应用 + * @param serverName: server 名 + * @param nodeName : node id + * @param version : server 版本 + * @param user : 发布者 + */ + int setPatchInfo(const string & app, const string & serverName, const string & nodeName, + const string & version, const string & user); + + /** + * 自动伸缩时调用的灰度发布接口 + * + * @param app: 应用 + * @param servername: server 名 + * @param nodename : node id + * @param status : 流量状态,NORMAL-正常流量,NO_FLOW-无流量 + * + * @return : 0-成功 others-失败 + */ + int gridPatchServer(const string & app, const string & servername, const string & nodename, const string &status); + + /** + * 轮询数据库,将心跳超时的registry设为不存活 + * @param iTiemout 超时时间 + * @return + */ + int checkRegistryTimeout(unsigned uTimeout); + + /** + * 更新registry信息到db + */ + int updateRegistryInfo2Db(bool bRegHeartbeatOff); + + + /** + * 根据ip获取组id + * @return int <0 失败 其它正常 + */ + int getGroupId(const string& ip); + + /** + * 加载IP物理分组信息 + */ + int loadIPPhysicalGroupInfo(); + +// int getServerInfo(const tars::srvRequestInfo & info,vector& vServerInfo); +protected: + //mysql连接对象 + tars::TC_Mysql _mysqlReg; + + //node节点代理列表 + static map _mapNodePrxCache; + static TC_ThreadLock _NodePrxLock; + + //匹配分组信息 + static vector > _serverGroupRule; + + //用于初始化保护 + static TC_ThreadLock _mutex; + + //分组信息 + static map _serverGroupCache; + static map _groupNameIDCache; +}; + +#endif diff --git a/AdminRegistryServer/ExecuteTask.cpp b/AdminRegistryServer/ExecuteTask.cpp new file mode 100644 index 00000000..52c8ad38 --- /dev/null +++ b/AdminRegistryServer/ExecuteTask.cpp @@ -0,0 +1,626 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "ExecuteTask.h" +#include "servant/Application.h" +#include "util/tc_timeprovider.h" + +extern TC_Config * g_pconf; + +TaskList::TaskList(const TaskReq &taskReq) +: _taskReq(taskReq) +{ + _adminPrx = CommunicatorFactory::getInstance()->getCommunicator()->stringToProxy(g_pconf->get("/tars/objname", "")); + + _taskRsp.taskNo = _taskReq.taskNo; + _taskRsp.serial = _taskReq.serial; + _taskRsp.userName = _taskReq.userName; + + for (size_t i=0; i < taskReq.taskItemReq.size(); i++) + { + TaskItemRsp rsp; + rsp.req = taskReq.taskItemReq[i]; + rsp.startTime = ""; + rsp.endTime = ""; + rsp.status = EM_I_NOT_START; + rsp.statusInfo= etos(rsp.status); + + _taskRsp.taskItemRsp.push_back(rsp); + } + + _createTime = TC_TimeProvider::getInstance()->getNow(); +} + + +TaskRsp TaskList::getTaskRsp() +{ + TC_LockT lock(*this); + + return _taskRsp; +} + + +void TaskList::setRspInfo(size_t index, bool start, EMTaskItemStatus status) +{ + TaskItemRsp rsp; + map info; + { + TC_LockT lock(*this); + + if (start) + { + _taskRsp.taskItemRsp[index].startTime = TC_Common::now2str("%Y-%m-%d %H:%M:%S"); + info["start_time"] = _taskRsp.taskItemRsp[index].startTime; + } + else + { + _taskRsp.taskItemRsp[index].endTime = TC_Common::now2str("%Y-%m-%d %H:%M:%S"); + info["end_time"] = _taskRsp.taskItemRsp[index].endTime; + } + + _taskRsp.taskItemRsp[index].status = status; + info["status"] = TC_Common::tostr(_taskRsp.taskItemRsp[index].status); + + _taskRsp.taskItemRsp[index].statusInfo = etos(status); + + rsp = _taskRsp.taskItemRsp[index]; + } + + try + { + _adminPrx->setTaskItemInfo(rsp.req.itemNo, info); + } + catch (exception &ex) + { +// log = ex.what(); + TLOGERROR("TaskList::setRspInfo error:" << ex.what() << endl); + } +} + +void TaskList::setRspLog(size_t index, const string &log) +{ + TaskItemRsp rsp; + map info; + { + TC_LockT lock(*this); + + _taskRsp.taskItemRsp[index].executeLog = log; + + rsp = _taskRsp.taskItemRsp[index]; + + info["log"] = _taskRsp.taskItemRsp[index].executeLog; + } + + try + { + _adminPrx->setTaskItemInfo(rsp.req.itemNo, info); + } + catch (exception &ex) + { +// log = ex.what(); + TLOGERROR("TaskList::setRspLog error:" << ex.what() << endl); + } +} + +EMTaskItemStatus TaskList::start(const TaskItemReq &req, string &log) +{ + int ret = -1; + try + { + ret = _adminPrx->startServer(req.application, req.serverName, req.nodeName, log); + if (ret == 0) + return EM_I_SUCCESS; + } + catch (exception &ex) + { + log = ex.what(); + TLOGERROR("TaskList::executeSingleTask startServer error:" << log << endl); + } + + return EM_I_FAILED; +} + +EMTaskItemStatus TaskList::restart(const TaskItemReq &req, string &log) +{ + int ret = -1; + try + { + ret = _adminPrx->restartServer(req.application, req.serverName, req.nodeName, log); + if (ret == 0) + return EM_I_SUCCESS; + } + catch (exception &ex) + { + log = ex.what(); + TLOGERROR("TaskList::restartServer error:" << log << endl); + } + + return EM_I_FAILED; +} + +EMTaskItemStatus TaskList::undeploy(const TaskItemReq &req, string &log) +{ + int ret = -1; + try + { + ret = _adminPrx->undeploy(req.application, req.serverName, req.nodeName, req.userName, log); + if (ret == 0) + return EM_I_SUCCESS; + } + catch (exception &ex) + { + log = ex.what(); + TLOGERROR("TaskList::undeploy error:" << log << endl); + } + + return EM_I_FAILED; +} + +EMTaskItemStatus TaskList::stop(const TaskItemReq &req, string &log) +{ + int ret = -1; + try + { + ret = _adminPrx->stopServer(req.application, req.serverName, req.nodeName, log); + if (ret == 0) + return EM_I_SUCCESS; + } + catch (exception &ex) + { + log = ex.what(); + TLOGERROR("TaskList::stop error:" << log << endl); + } + + return EM_I_FAILED; +} + +string TaskList::get(const string &name, const map ¶meters) +{ + map::const_iterator it = parameters.find(name); + if (it == parameters.end()) + { + return ""; + } + return it->second; +} + +EMTaskItemStatus TaskList::patch(const TaskItemReq &req, string &log) +{ + + try + { + + int ret = EM_TARS_UNKNOWN_ERR; + + TLOGDEBUG("TaskList::patch:" << TC_Common::tostr(req.parameters.begin(), req.parameters.end()) << endl); + + string patchId = get("patch_id", req.parameters); + string patchType = get("patch_type", req.parameters); + + tars::PatchRequest patchReq; + patchReq.appname = req.application; + patchReq.servername = req.serverName; + patchReq.nodename = req.nodeName; + patchReq.version = patchId; + patchReq.user = req.userName; + + try + { + ret = _adminPrx->batchPatch(patchReq, log); + } + catch (exception &ex) + { + log = ex.what(); + TLOGERROR("TaskList::patch batchPatch error:" << log << endl); + return EM_I_FAILED; + } + + if (ret != EM_TARS_SUCCESS) + { + log = "batchPatch err:" + log; + return EM_I_FAILED; + } + + while (true) + { + PatchInfo pi; + + try + { + ret = _adminPrx->getPatchPercent(req.application, req.serverName, req.nodeName, pi); + } + catch (exception &ex) + { + log = ex.what(); + TLOGERROR("TaskList::patch getPatchPercent error, ret:" << ret << endl); + } + + if (ret != 0) + { + _adminPrx->updatePatchLog(req.application, req.serverName, req.nodeName, patchId, req.userName, patchType, false); + TLOGERROR("TaskList::patch getPatchPercent error, ret:" << ret << endl); + return EM_I_FAILED; + } + + if(pi.iPercent == 100 && pi.bSucc) + { + _adminPrx->updatePatchLog(req.application, req.serverName, req.nodeName, patchId, req.userName, patchType, true); + TLOGDEBUG("TaskList::patch getPatchPercent ok, percent:" << pi.iPercent << "%" << endl); + break; + } + + TLOGDEBUG("TaskList::patch getPatchPercent percent:" << pi.iPercent << "%, succ:" << pi.bSucc << endl); + + sleep(1); + } + + } + catch (exception &ex) + { + TLOGERROR("TaskList::patch error:" << ex.what() << endl); + return EM_I_FAILED; + } + return EM_I_SUCCESS; +} + +EMTaskItemStatus TaskList::gridPatchServer(const TaskItemReq &req, string &log) +{ + int ret = -1; + try + { + TLOGDEBUG("TaskList::grid_server:" << TC_Common::tostr(req.parameters.begin(), req.parameters.end()) << endl); + + string status = get("grid_status", req.parameters); + + vector gridDescList; + + tars::ServerGridDesc serverGridDesc; + serverGridDesc.application = req.application; + serverGridDesc.servername = req.serverName; + serverGridDesc.nodename = req.nodeName; + + if(TC_Common::strto(status) == tars::NORMAL) + serverGridDesc.status = tars::NORMAL; + else if(TC_Common::strto(status) == tars::NO_FLOW) + serverGridDesc.status = tars::NO_FLOW; + else if(TC_Common::strto(status) == tars::GRID) + serverGridDesc.status = tars::GRID; + else + serverGridDesc.status = tars::NORMAL; + + gridDescList.push_back(serverGridDesc); + + vector gridFailDescList; + ret = _adminPrx->gridPatchServer(gridDescList, gridFailDescList,log); + if (ret == 0) + return EM_I_SUCCESS; + } + catch (exception &ex) + { + log = ex.what(); + TLOGERROR("TaskList::gridPatchServer error:" << log << endl); + } + + return EM_I_FAILED; +} +EMTaskItemStatus TaskList::executeSingleTask(size_t index, const TaskItemReq &req) +{ + TLOGDEBUG("TaskList::executeSingleTask: taskNo=" << req.taskNo + << ",application=" << req.application + << ",serverName=" << req.serverName + << ",nodeName=" << req.nodeName + << ",setName=" << req.setName + << ",command=" << req.command << endl); + + EMTaskItemStatus ret = EM_I_FAILED; + string log; + if (req.command == "stop") + { + ret = stop(req, log); + } + else if (req.command == "start") + { + ret = start(req, log); + } + else if (req.command == "restart") + { + ret = restart(req, log); + } + else if (req.command == "patch_tars") + { + ret = patch(req, log); + if (ret == EM_I_SUCCESS && get("bak_flag", req.parameters) != "1") + { + //不是备机, 需要重启 + ret = restart(req, log); + } + } + else if (req.command == "undeploy_tars") + { + ret = undeploy(req, log); + } + else if (req.command == "grid_server") + { + ret = gridPatchServer(req,log); + } + else + { + ret = EM_I_FAILED; + log = "command not support!"; + TLOGDEBUG("TaskList::executeSingleTask command not support!" << endl); + } + + setRspLog(index, log); + + return ret; +} + +////////////////////////////////////////////////////////////////////////////// +TaskListSerial::TaskListSerial(const TaskReq &taskReq) +: TaskList(taskReq) +{ + _pool.init(1); + _pool.start(); +} + +void TaskListSerial::execute() +{ + TLOGDEBUG("TaskListSerial::execute" << endl); + + auto cmd = std::bind(&TaskListSerial::doTask, this); + _pool.exec(cmd); +} + +void TaskListSerial::doTask() +{ + size_t len = 0; + { + TC_LockT lock(*this); + len = _taskReq.taskItemReq.size(); + } + + EMTaskItemStatus status = EM_I_SUCCESS; + + for (size_t i=0; i < len; i++) + { + TaskItemReq req; + + setRspInfo(i, true, EM_I_RUNNING); + { + TC_LockT lock(*this); + + req = _taskReq.taskItemReq[i]; + } + + if (EM_I_SUCCESS == status) + { + status = executeSingleTask(i, req); + } + else + { + //上一个任务不成功, 后续的任务都cancel掉 + status = EM_I_CANCEL; + } + + setRspInfo(i, false, status); + } +} + +////////////////////////////////////////////////////////////////////////////// +TaskListParallel::TaskListParallel(const TaskReq &taskReq) +: TaskList(taskReq) +{ + //最大并行线程数 + size_t num = taskReq.taskItemReq.size() > 10 ? 10 : taskReq.taskItemReq.size(); + _pool.init(num); + _pool.start(); +} + +void TaskListParallel::execute() +{ + TLOGDEBUG("TaskListParallel::execute" << endl); + + TC_LockT lock(*this); + + for (size_t i=0; i < _taskReq.taskItemReq.size(); i++) + { + auto cmd = std::bind(&TaskListParallel::doTask, this, _taskReq.taskItemReq[i], i); + _pool.exec(cmd); + } +} + +void TaskListParallel::doTask(TaskItemReq req, size_t index) +{ + setRspInfo(index, true, EM_I_RUNNING); + + //do work + TLOGDEBUG("TaskListParallel::executeTask: taskNo=" << req.taskNo + << ",application=" << req.application + << ",serverName=" << req.serverName + << ",setName=" << req.setName + << ",command=" << req.command << endl); + + EMTaskItemStatus status = executeSingleTask(index, req); + + setRspInfo(index, false, status); +} + +///////////////////////////////////////////////////////////////////////////// + +ExecuteTask::ExecuteTask() +{ + _terminate = false; + start(); +} + +ExecuteTask::~ExecuteTask() +{ + terminate(); +} + +void ExecuteTask::terminate() +{ + _terminate = true; + TC_LockT lock(*this); + notifyAll(); +} + +void ExecuteTask::run() +{ + const time_t diff = 2*60;//2分钟 + while (!_terminate) + { + { + TC_ThreadLock::Lock lock(*this); + map::iterator it = _task.begin(); + while (it != _task.end()) + { + if(TC_TimeProvider::getInstance()->getNow() - it->second->getCreateTime() > diff) + { + TLOGDEBUG("==============ExecuteTask::run, delete old task, taskNo=" << it->first << endl); + TaskList *tmp = it->second; + _task.erase(it++); + delete tmp; + } + else + { + ++it; + } + } + } + + { + TC_LockT lock(*this); + timedWait(5*1000); + } + } +} + + +int ExecuteTask::addTaskReq(const TaskReq &taskReq) +{ + TLOGDEBUG("ExecuteTask::addTaskReq" << + ", taskNo=" << taskReq.taskNo << + ", size=" << taskReq.taskItemReq.size() << + ", serial=" << taskReq.serial << + ", userName="<< taskReq.userName << endl); + + TaskList *p = NULL; + if (taskReq.serial) + { + p = new TaskListSerial(taskReq); + } + else + { + p = new TaskListParallel(taskReq); + } + + { + TC_ThreadLock::Lock lock(*this); + + _task[taskReq.taskNo] = p; + + //删除历史数据, 当然最好是在定时独立做, 放在这里主要是途方便 + map::iterator it = _task.begin(); + while (it != _task.end()) + { + static time_t diff = 24 *60 *60;//1天 + //大于两天数据任务就干掉 + if(TC_TimeProvider::getInstance()->getNow() - it->second->getCreateTime() > diff) + { + TaskList *temp = it->second; + + _task.erase(it++); + + delete temp; + temp = NULL; + } + else + { + ++it; + } + } + } + + p->execute(); + + return 0; +} + +bool ExecuteTask::getTaskRsp(const string &taskNo, TaskRsp &taskRsp) +{ + TLOGDEBUG("ExecuteTask::getTaskRsp, taskNo=" << taskNo << endl); + + TC_ThreadLock::Lock lock(*this); + + map::iterator it = _task.find(taskNo); + + if( it == _task.end()) + { + return false; + } + + taskRsp = (it->second)->getTaskRsp(); + + ExecuteTask::getInstance()->checkTaskRspStatus(taskRsp); + + return true; +} + + +void ExecuteTask::checkTaskRspStatus(TaskRsp &taskRsp) +{ + size_t not_start = 0; + size_t running = 0; + size_t success = 0; + size_t failed = 0; + size_t cancel = 0; + + for (unsigned i = 0; i < taskRsp.taskItemRsp.size(); i++) + { + TaskItemRsp &rsp = taskRsp.taskItemRsp[i]; + + switch (rsp.status) + { + case EM_I_NOT_START: + ++not_start; + break; + case EM_I_RUNNING: + ++running; + break; + case EM_I_SUCCESS: + ++success; + break; + case EM_I_FAILED: + ++failed; + break; + case EM_I_CANCEL: + ++cancel; + break; + } + } + + if (not_start == taskRsp.taskItemRsp.size()) taskRsp.status = EM_T_NOT_START; + else if (running == taskRsp.taskItemRsp.size()) taskRsp.status = EM_T_RUNNING; + else if (success == taskRsp.taskItemRsp.size()) taskRsp.status = EM_T_SUCCESS; + else if (failed == taskRsp.taskItemRsp.size()) taskRsp.status = EM_T_FAILED; + else if (cancel == taskRsp.taskItemRsp.size()) taskRsp.status = EM_T_CANCEL; + else taskRsp.status = EM_T_PARIAL; + +} + + + diff --git a/AdminRegistryServer/ExecuteTask.h b/AdminRegistryServer/ExecuteTask.h new file mode 100644 index 00000000..2a06c101 --- /dev/null +++ b/AdminRegistryServer/ExecuteTask.h @@ -0,0 +1,148 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __EXECUTE_TASK_H__ +#define __EXECUTE_TASK_H__ + +#include +#include "util/tc_thread_pool.h" +#include "util/tc_singleton.h" +#include "AdminReg.h" + +using namespace tars; + +class TaskList : public TC_ThreadMutex +{ +public: + /** + * 构造函数 + */ + TaskList(const TaskReq &taskReq); + + /** + * 得到返回任务 + */ + TaskRsp getTaskRsp(); + + + virtual void execute() = 0; + /** + * 创建时间 + */ + time_t getCreateTime() { return _createTime; } + +protected: + + //设置应答信息 + void setRspInfo(size_t index, bool start, EMTaskItemStatus status); + + //设置应答的log + void setRspLog(size_t index, const string &log); + + EMTaskItemStatus executeSingleTask(size_t index, const TaskItemReq &req); + + EMTaskItemStatus start (const TaskItemReq &req, string &log); + EMTaskItemStatus restart (const TaskItemReq &req, string &log); + EMTaskItemStatus stop (const TaskItemReq &req, string &log); + EMTaskItemStatus patch (const TaskItemReq &req, string &log); + EMTaskItemStatus undeploy(const TaskItemReq &req, string &log); + EMTaskItemStatus gridPatchServer(const TaskItemReq &req, string &log); + string get(const string &name, const map ¶meters); + +protected: + + //线程池 + TC_ThreadPool _pool; + //请求任务 + TaskReq _taskReq; + //返回任务 + TaskRsp _taskRsp; + + AdminRegPrx _adminPrx; + + time_t _createTime; +}; + +class TaskListSerial : public TaskList +{ +public: + TaskListSerial(const TaskReq &taskReq); + + virtual void execute(); + +protected: + void doTask(); +}; + +class TaskListParallel : public TaskList +{ +public: + TaskListParallel(const TaskReq &taskReq); + + virtual void execute(); + +protected: + void doTask(TaskItemReq req, size_t index); +}; + +class ExecuteTask : public TC_Singleton, public TC_ThreadLock, public TC_Thread +{ +public: + + ExecuteTask(); + + ~ExecuteTask(); + + virtual void run(); + + void terminate(); + + /** + * 添加任务请求 + * + * @param taskList + * @param serial + * @param current + * + * @return string + */ + int addTaskReq(const TaskReq &taskReq); + + /** + * 获取任务状态 + * + * @param taskIdList : 任务列表id + * + * @return 任务状态 + */ + bool getTaskRsp(const string &taskNo, TaskRsp &taskRsp); + + /** + * 检查task的状态 + * + * @param taskRsp + */ + void checkTaskRspStatus(TaskRsp &taskRsp); + +protected: + + map _task; + + //线程结束标志 + bool _terminate; +}; + +#endif diff --git a/AdminRegistryServer/util.h b/AdminRegistryServer/util.h new file mode 100644 index 00000000..cd7500e9 --- /dev/null +++ b/AdminRegistryServer/util.h @@ -0,0 +1,26 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __UTIL_H_ +#define __UTIL_H_ + +#include "util/tc_common.h" +#include "servant/tars_logger.h" + +#define FILE_FUN __FILE__<<":"<<__FUNCTION__<<":"<<__LINE__<<"|" +#define FILE_FUN_STR TC_Common::tostr(__FILE__)+":"+TC_Common::tostr(__FUNCTION__)+":"+TC_Common::tostr(__LINE__)+"|" + +#endif diff --git a/AuthServer/AuthImp.cpp b/AuthServer/AuthImp.cpp new file mode 100644 index 00000000..9bd71a04 --- /dev/null +++ b/AuthServer/AuthImp.cpp @@ -0,0 +1,164 @@ +#include "AuthImp.h" +#include "AuthServer.h" +#include "servant/TarsLogger.h" + +using namespace tars; + +std::string tableName = "t_auth_info"; + +AuthImp::AuthImp() : _mysql(NULL) +{ +} + +AuthImp::~AuthImp() +{ + delete _mysql; +} + +void AuthImp::initialize() +{ + assert (!_mysql); + _mysql = new TC_Mysql(); + + extern TC_Config * g_pconf; + + TC_DBConf dbConf; + dbConf.loadFromMap(g_pconf->getDomainMap("/tars/db")); + _mysql->init(dbConf); + + std::string createTbl = (*g_pconf)["/tars/"]; + _mysql->execute(createTbl); +} + +int AuthImp::authProcess(const AuthRequest& request, TarsCurrentPtr current) +{ + string sSql("select token from "); + sSql += tableName; + sSql += " where application ='"; + sSql += request.sKey.sApplication; + sSql += "' and server ='"; + sSql += request.sKey.sServer; + sSql += "' and objname ='"; + sSql += request.sKey.sObjName; + sSql += "';"; + + TC_Mysql::MysqlData result; + try { + result = _mysql->queryRecord(sSql); + } + catch (const TC_Mysql_Exception& e) { + TLOGDEBUG("exp : " << e.what() << endl); + return AUTH_ERROR; + } + + assert (result.size() <= 1); + if (result.size() == 0) + { + return AUTH_WRONG_OBJ; + } + else + { + string token = result[0]["token"]; + TLOGDEBUG("got token from mysql " << token << endl); + if (token != request.sToken) + { + TLOGERROR("wrong token " << request.sToken << endl); + return AUTH_WRONG_TOKEN; + } + } + + return AUTH_SUCC; +} + + +vector AuthImp::getTokens(const tars::TokenRequest& request,tars::TarsCurrentPtr current) +{ + vector rsp; + for (vector::const_iterator it(request.vObjName.begin()); it != request.vObjName.end(); ++ it) + { + string sSql; + sSql += "select application, server, token from " + tableName + " where objname = '"; + sSql += *it; + sSql += "';"; + + TC_Mysql::MysqlData result; + try { + result = _mysql->queryRecord(sSql); + } + catch (const TC_Mysql_Exception& e) { + TLOGDEBUG("queryRecord exp " << e.what() << endl); + continue; + } + + tars::TokenResponse tmp; + tmp.sObjName = *it; + for (size_t i = 0; i < result.size(); ++ i) + { + // app.server + std::string key = result[i]["application"] + "." + result[i]["server"]; + tmp.mTokens[key] = result[i]["token"]; + } + rsp.push_back(tmp); + } + + return rsp; +} + + +#if 0 + id | int(11) | NO | PRI | NULL | auto_increment | + | application | varchar(128) | YES | MUL | | | + | server | varchar(128) | YES | | NULL | | + | objname | varchar(128) | YES | | | | + | token | varchar(128) | NO | | | | +#endif +tars::ApplyTokenResponse AuthImp::applyToken(const tars::ApplyTokenRequest& request,tars::TarsCurrentPtr current) +{ + // gen secret key; + char token[32] = ""; + TC_Common::getRandomHexChars(token, 16); + std::string sToken(token); + + std::ostringstream sql; + sql << "insert into " + tableName + " (application, server, objname, token) values('"; + sql << request.sKey.sApplication << "','" << request.sKey.sServer << "','" << request.sKey.sObjName << "','"; + sql << sToken << "');"; + + try { + string sSql = sql.str(); + TLOGDEBUG("exec insert:" << sSql << endl); + _mysql->execute(sSql); + } + catch (const TC_Mysql_Exception& e) { + TLOGDEBUG("applySecret exp " << e.what() << endl); + sToken.clear(); + } + + tars::ApplyTokenResponse rsp; + rsp.sKey = request.sKey; + rsp.sToken = sToken; + return rsp; +} + +int AuthImp::deleteToken(const tars::DeleteTokenRequest& request,tars::TarsCurrentPtr current) +{ + //DELETE FROM tbl_name + // WHERE which rows to delete; + + std::ostringstream sql; + sql << "delete from " + tableName + " where application='"; + sql << request.sKey.sApplication << "' and server='" << request.sKey.sServer << "' and objname='" << request.sKey.sObjName << "';"; + + try { + string sSql = sql.str(); + TLOGDEBUG("exec delete :" << sSql << endl); + _mysql->execute(sSql); + } + catch (const TC_Mysql_Exception& e) { + TLOGDEBUG("delete exp " << e.what() << endl); + return -1; + } + + return 0; +} + diff --git a/AuthServer/AuthImp.h b/AuthServer/AuthImp.h new file mode 100644 index 00000000..fe8ed36a --- /dev/null +++ b/AuthServer/AuthImp.h @@ -0,0 +1,43 @@ +#ifndef _AUTHIMP_H_ +#define _AUTHIMP_H_ + +#include "Auth.h" +#include "util/tc_common.h" +#include "util/tc_config.h" +#include "util/tc_mysql.h" + +class AuthImp : public tars::Auth +{ +public: + AuthImp(); + ~AuthImp(); + + /** + * ʼ + * + * @return int + */ + virtual void initialize(); + + /** + * ˳ + */ + virtual void destroy() {} + + /** + * process + */ + virtual int authProcess(const tars::AuthRequest & request,tars::TarsCurrentPtr current); + virtual vector getTokens(const tars::TokenRequest& request,tars::TarsCurrentPtr current); + virtual tars::ApplyTokenResponse applyToken(const tars::ApplyTokenRequest& request,tars::TarsCurrentPtr current); + virtual int deleteToken(const tars::DeleteTokenRequest& request,tars::TarsCurrentPtr current); + +private: + /** + * mysql + */ + TC_Mysql* _mysql; +}; + +#endif + diff --git a/AuthServer/AuthServer.cpp b/AuthServer/AuthServer.cpp new file mode 100644 index 00000000..0c797002 --- /dev/null +++ b/AuthServer/AuthServer.cpp @@ -0,0 +1,14 @@ +#include "AuthServer.h" +#include "AuthImp.h" + +void AuthServer::initialize() +{ + //Ӷ + addServant(ServerConfig::Application + "." + ServerConfig::ServerName + ".AuthObj"); +} + +void AuthServer::destroyApp() +{ + cout << "AuthServer::destroyApp ok" << endl; +} + diff --git a/AuthServer/AuthServer.h b/AuthServer/AuthServer.h new file mode 100644 index 00000000..40fb1c06 --- /dev/null +++ b/AuthServer/AuthServer.h @@ -0,0 +1,23 @@ +#ifndef _AUTH_SERVER_H_ +#define _AUTH_SERVER_H_ + +#include "servant/Application.h" + +using namespace tars; + +class AuthServer : public Application +{ +protected: + /** + * ʼ, ̵ֻһ + */ + virtual void initialize(); + + /** + * , ÿ̶һ + */ + virtual void destroyApp(); +}; + +#endif + diff --git a/AuthServer/CMakeLists.txt b/AuthServer/CMakeLists.txt new file mode 100644 index 00000000..3f8721f7 --- /dev/null +++ b/AuthServer/CMakeLists.txt @@ -0,0 +1,7 @@ + +set(MODULE "tarsauth") + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/deploy/${MODULE}) + +complice_module(${MODULE}) + diff --git a/AuthServer/main.cpp b/AuthServer/main.cpp new file mode 100644 index 00000000..02dbd99a --- /dev/null +++ b/AuthServer/main.cpp @@ -0,0 +1,26 @@ +#include +#include "AuthServer.h" + +using namespace tars; + +TC_Config * g_pconf; + +int main(int argc, char *argv[]) +{ + try + { + AuthServer app; + g_pconf = & app.getConfig(); + app.main(argc, argv); + + app.waitForShutdown(); + } + catch(exception &ex) + { + cerr<< ex.what() << endl; + } + + return 0; +} + + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..93cdd897 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,197 @@ +cmake_minimum_required(VERSION 2.8) + +project(framework) + +set(CMAKE_VERBOSE_MAKEFILE off) + +set(MYSQL_DIR_INC "/usr/local/mysql/include") +set(MYSQL_DIR_LIB "/usr/local/mysql/lib") + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -O2 -Wall -Wno-deprecated") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -Wall -Wno-deprecated") + +#set(CMAKE_BUILD_TYPE "Debug") + +set(TARS_VERSION "1.1.0") +add_definitions(-DTARS_VERSION="${TARS_VERSION}") + +set(INSTALL_PREFIX "/usr/local/tars/cpp") + +set(CMAKE_INSTALL_PREFIX ${INSTALL_PREFIX}) + +add_subdirectory(tarscpp) +set(TARS2CPP "${tools_BINARY_DIR}/tars2cpp/tars2cpp") + +include_directories(${util_SOURCE_DIR}/include) +include_directories(${servant_SOURCE_DIR}) +include_directories(${MYSQL_DIR_INC}) +include_directories("thirdparty/rapidjson/include") + +link_libraries(tarsservant tarsutil) +link_libraries(${MYSQL_DIR_LIB}/libmysqlclient.a) +link_libraries(pthread z dl rt) + +macro(complice_module MODULE) + + include_directories(${PROJECT_SOURCE_DIR}/tarscpp/servant/protocol/framework) + include_directories(${servant_SOURCE_DIR}/servant) + + aux_source_directory(. DIR_SRCS) + + add_executable(${MODULE} ${DIR_SRCS}) + add_dependencies(${MODULE} FRAMEWORK-PROTOCOL) + +endmacro() + +#调用tars2cpp, 生成tars对应的文件 +macro(complice_tars OUT_DEPENDS_LIST) + set(DEPENDS_LIST) + + set(SERVANT_PROTOCOL "${servant_SOURCE_DIR}/protocol/servant") + + set(CLEAN_LIST) + + set(CURRENT_PROTOCOL_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + + FILE(GLOB SRC_LIST "${CURRENT_PROTOCOL_DIR}/*.tars") + + foreach (FILE ${SRC_LIST}) + + #设置tars文件搜索路径 + set(INCLUDE_STRING "--include=\"${SERVANT_PROTOCOL}\"") + + get_filename_component(NAME_WE ${FILE} NAME_WE) + + # 生成tars文件 + set(TARS_IN ${FILE}) + set(TARS_H ${NAME_WE}.h) + + add_custom_command( + OUTPUT ${CURRENT_PROTOCOL_DIR}/${TARS_H} + WORKING_DIRECTORY ${CURRENT_PROTOCOL_DIR} + DEPENDS tars2cpp + COMMAND ${TARS2CPP} --with-tars ${INCLUDE_STRING} ${TARS_IN} + COMMENT "${TARS2CPP} --with-tars ${INCLUDE_STRING} ${TARS_IN}") + + list(APPEND DEPENDS_LIST ${CURRENT_PROTOCOL_DIR}/${TARS_H}) + + #设置需要清除的文件 + list(APPEND CLEAN_LIST ${CURRENT_PROTOCOL_DIR}/${NAME_WE}.h) + + endforeach () + + set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${CLEAN_LIST}") + + set(OUT_DEPENDS_LIST ${DEPENDS_LIST}) +endmacro() + +add_subdirectory(tarscpp/servant/protocol/framework) +add_subdirectory(ConfigServer) +add_subdirectory(NodeServer) +add_subdirectory(NotifyServer) +add_subdirectory(PatchServer) +add_subdirectory(AdminRegistryServer) +add_subdirectory(RegistryServer) +add_subdirectory(PropertyServer) +add_subdirectory(LogServer) +add_subdirectory(patchclient) +add_subdirectory(StatServer) +add_subdirectory(QueryStatServer) +add_subdirectory(QueryPropertyServer) +add_subdirectory(AuthServer) +############################################################################################ +# 打包deploy, 用于部署 + +set(DEPENDS_LIST) +list(APPEND DEPENDS_LIST tarsnode) +list(APPEND DEPENDS_LIST tarsregistry) +list(APPEND DEPENDS_LIST tarsAdminRegistry) +list(APPEND DEPENDS_LIST tarspatch) +list(APPEND DEPENDS_LIST tarsconfig) + +#set(FRAMEWORK-TGZ "${CMAKE_BINARY_DIR}/framework-tmp.tgz") +set(FRAMEWORK-TGZ "${CMAKE_BINARY_DIR}/framework.tgz") + +#需要压缩的文件 +set(MODULES "tars_install.sh") +set(MODULES "${MODULES} tarsnode_install.sh") + +foreach (MODULE ${DEPENDS_LIST}) + set(MODULES "${MODULES} ${MODULE}") +endforeach () + +#打包脚本 +SET(RUN_DEPLOY_COMMAND_FILE "${PROJECT_BINARY_DIR}/run-deploy-framework.cmake") +FILE(WRITE ${RUN_DEPLOY_COMMAND_FILE} "#deploy framework-tar\n") +FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} "EXECUTE_PROCESS(\n") +FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} "WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/deploy/\n") +FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} "COMMAND cp -rf ${PROJECT_SOURCE_DIR}/deploy/tars_install.sh .\n") +FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} "COMMAND cp -rf ${PROJECT_SOURCE_DIR}/deploy/tarsnode_install.sh .\n") +foreach (MODULE ${DEPENDS_LIST}) + FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} "COMMAND cp -rf ${PROJECT_SOURCE_DIR}/deploy/${MODULE} .\n") +endforeach () +FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} ")\n") +FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} "EXECUTE_PROCESS(\n") +FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} "WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/deploy/\n") +FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} "COMMAND tar czfv ${FRAMEWORK-TGZ} ${MODULES}\n") +#FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} "COMMAND mv ${FRAMEWORK-TGZ} ${CMAKE_BINARY_DIR}/framework.tgz\n") +FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} ")\n") + +#执行命令 +add_custom_command(OUTPUT ${FRAMEWORK-TGZ} + COMMAND ${CMAKE_COMMAND} -P ${RUN_DEPLOY_COMMAND_FILE} + COMMENT "call ${RUN_DEPLOY_COMMAND_FILE}") + +add_custom_target(framework-tar + DEPENDS ${FRAMEWORK-TGZ} ${DEPENDS_LIST}) + +############################################################################################ +# 打包tarsnotify tarsstat tarsproperty tarslog tarsauth +set(TARSQUERYSTAT tarsquerystat) +set(TARSQUERYPROPERTY tarsqueryproperty) + +set(DEPENDS_LIST) +list(APPEND DEPENDS_LIST tarsnotify) +list(APPEND DEPENDS_LIST tarsstat) +list(APPEND DEPENDS_LIST tarsproperty) +list(APPEND DEPENDS_LIST tarslog) +list(APPEND DEPENDS_LIST tarsquerystat) +list(APPEND DEPENDS_LIST tarsqueryproperty) +list(APPEND DEPENDS_LIST tarsauth) + + +foreach (MODULE ${DEPENDS_LIST}) + + #set(MODULE-TGZ "${CMAKE_BINARY_DIR}/${MODULE}-tmp.tgz") + set(MODULE-TGZ "${CMAKE_BINARY_DIR}/${MODULE}.tgz") + + #打包脚本 + SET(RUN_DEPLOY_COMMAND_FILE "${PROJECT_BINARY_DIR}/run-deploy-${MODULE}.cmake") + FILE(WRITE ${RUN_DEPLOY_COMMAND_FILE} "#deploy ${MODULE}-tar\n") + FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} "EXECUTE_PROCESS(\n") + FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} "WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/deploy/\n") + FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} "COMMAND tar czfv ${MODULE-TGZ} ${MODULE}\n") + #FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} "COMMAND mv ${MODULE-TGZ} ${CMAKE_BINARY_DIR}/${MODULE}.tgz\n") + FILE(APPEND ${RUN_DEPLOY_COMMAND_FILE} ")\n") + + add_custom_command(OUTPUT ${MODULE-TGZ} + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -P ${RUN_DEPLOY_COMMAND_FILE} + COMMENT "call ${RUN_DEPLOY_COMMAND_FILE}") + + add_custom_target(${MODULE}-tar DEPENDS ${MODULE-TGZ} ${MODULE}) +endforeach () + +############################################################################################ + + + + + + + + + + + + diff --git a/ConfigServer/CMakeLists.txt b/ConfigServer/CMakeLists.txt new file mode 100644 index 00000000..49846b4f --- /dev/null +++ b/ConfigServer/CMakeLists.txt @@ -0,0 +1,8 @@ + +set(MODULE "tarsconfig") + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/deploy/${MODULE}/bin) + +complice_module(${MODULE}) + + diff --git a/ConfigServer/ConfigImp.cpp b/ConfigServer/ConfigImp.cpp new file mode 100644 index 00000000..749ebd25 --- /dev/null +++ b/ConfigServer/ConfigImp.cpp @@ -0,0 +1,970 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "ConfigImp.h" +#include "ConfigServer.h" + +extern TC_Config * g_pconf; + +#define CHECKLIMIT(a,b,c,f) do{\ + if(IsLimited((a),(b),(c),(f)))\ + {\ + return 0;\ + }}while(0) + +using namespace tars; + +map > ConfigImp::_loadConfigLimited; + +void ConfigImp::loadconf() +{ + TC_DBConf tcDBConf; + tcDBConf.loadFromMap(g_pconf->getDomainMap("/tars/db")); + _mysqlConfig.init(tcDBConf); + + _limitInterval = TC_Common::strto(g_pconf->get("/tars/limit", "10")); + _limitInterval = _limitInterval <= 0 ? 10 : _limitInterval; + _interval = TC_Common::strto(g_pconf->get("/tars/limit", "1")); + _interval = _interval <= 0 ? 1 : _interval; +} + +void ConfigImp::initialize() +{ + loadconf(); +} + +int ConfigImp::ListConfig(const string &app, const string &server, vector &vf,tars::TarsCurrentPtr current) +{ + try + { + string host = current->getIp(); + + TLOGDEBUG("ConfigImp::ListConfig app:" << app << "|server:" << server << "|host:" << host << endl); + + //查ip对应配置 + string sNULL(""); + string sSql = + "select filename from t_config_files " + "where server_name = '" + _mysqlConfig.escapeString(app+"."+server) + "' " + "and host='" + _mysqlConfig.escapeString(host) +"' " + "and level=" + TC_Common::tostr(eLevelIpServer) + " " + "and set_name ='" + _mysqlConfig.escapeString(sNULL) +"' " + "and set_area ='" + _mysqlConfig.escapeString(sNULL) +"' " + "and set_group ='" + _mysqlConfig.escapeString(sNULL) +"' "; + + TC_Mysql::MysqlData res = _mysqlConfig.queryRecord(sSql); + + TLOGDEBUG("ConfigImp::ListConfig sql:" << sSql << "|res.size:" << res.size() << endl); + + for(unsigned i=0; i vtSetDivisions = TC_Common::sepstr(sSetDivision, "."); + if(vtSetDivisions.size() != 3) + { + return false; + } + + sSetName = vtSetDivisions[0]; + sSetArea = vtSetDivisions[1]; + sSetGroup = vtSetDivisions[2]; + + return true; +} + +int ConfigImp::ListConfigByInfo(const ConfigInfo& configInfo, vector &vf,tars::TarsCurrentPtr current) +{ + try + { + string sHost = configInfo.host.empty() ? current->getIp() : configInfo.host; + + TLOGDEBUG("ConfigImp::ListConfigByInfo app:" << configInfo.appname << "|server:" << configInfo.servername << "|set:" << configInfo.setdivision << "|host:" << sHost << endl); + + string sCondition; + if(!configInfo.setdivision.empty()) + { + string sSetName,sSetArea,sSetGroup; + if(getSetInfo(sSetName,sSetArea,sSetGroup,configInfo.setdivision)) + { + sCondition += " and set_name='" +_mysqlConfig.escapeString(sSetName)+"' "; + sCondition += " and set_area='" +_mysqlConfig.escapeString(sSetArea)+"' "; + sCondition += " and set_group='"+_mysqlConfig.escapeString(sSetGroup)+"' "; + } + else + { + TLOGERROR("ConfigImp::ListConfigByInfo setdivision is invalid|setdivision:" << configInfo.setdivision << endl); + return -1; + } + } + else//兼容没有set信息的业务 + { + string sNULL(""); + sCondition += " and set_name='" + _mysqlConfig.escapeString(sNULL) +"' "; + sCondition += " and set_area='" + _mysqlConfig.escapeString(sNULL) +"' "; + sCondition += " and set_group='" + _mysqlConfig.escapeString(sNULL) +"' "; + } + + //查ip对应配置 + string sSql = + "select filename from t_config_files " + "where server_name = '" + _mysqlConfig.escapeString(configInfo.appname + "." + configInfo.servername) + "' " + "and host='" + _mysqlConfig.escapeString(sHost) + "' " + "and level=" + TC_Common::tostr(eLevelIpServer) + sCondition; + + TC_Mysql::MysqlData res = _mysqlConfig.queryRecord(sSql); + + TLOGDEBUG("ConfigImp::ListConfigByInfo sql:" << sSql << "|res.size:" << res.size() << endl); + + for(unsigned i=0; igetIp(),configInfo.filename); + + if(configInfo.bAppOnly || configInfo.servername.empty())//应用级配置或者set级配置 + { + iRet = loadAppConfigByInfo(configInfo,config,current); + } + else + { + iRet = loadConfigByHost(configInfo,config,current); + } + + return iRet; +} + +int ConfigImp::checkConfigByInfo(const ConfigInfo & configInfo, string &result,tars::TarsCurrentPtr current) +{ + TLOGDEBUG("ConfigImp::checkConfigByInfo app:" << configInfo.appname << "|server:" << configInfo.servername << "|filename:" << configInfo.filename << "|setdivsion:" << configInfo.setdivision << endl); + + int iRet = loadConfigByHost(configInfo,result,current); + if (iRet != 0) + { + TLOGERROR("ConfigImp::checkConfigByInfo loadConfigByHost fail." << endl); + return -1; + } + + try + { + TC_Config conf; + conf.parseString(result); + } + catch(exception &ex) + { + result = ex.what(); + TLOGERROR("ConfigImp::checkConfigByInfo exception:" << ex.what() << endl); + return -1; + } + + return 0; +} + +int ConfigImp::loadConfig(const std::string& app, const std::string& server, const std::string& fileName, string &config, tars::TarsCurrentPtr current) +{ + TLOGDEBUG("ConfigImp::loadConfig app:" << app << "|server:" << server << "|fileName:" << fileName << "|host:" << current->getIp() << endl); + + CHECKLIMIT(app,server,current->getIp(),fileName); + + if(!server.empty()) + { + return loadConfigByHost(app + "." + server, fileName, current->getIp(), config, current); + } + else + { + return loadAppConfig(app, fileName, config, current); + } +} + +int ConfigImp::loadConfigByHost(const std::string& appServerName, const std::string& fileName, const string &host, string &config, tars::TarsCurrentPtr current) +{ + TLOGDEBUG("ConfigImp::loadConfigByHost appServerName:" << appServerName << "|fileName:" << fileName << "|host:" << host << endl); + + int iRet = 0; + config = ""; + + //多配置文件的分割符 + string sSep = "\r\n\r\n"; + try + { + string sAllServerConfig(""); + int iAllConfigId = 0; + + //查公有配置 + string sNULL(""); + string sSql = + "select id,config from t_config_files " + "where server_name = '" + _mysqlConfig.escapeString(appServerName) + "' " + "and filename='" + _mysqlConfig.escapeString(fileName) + "' " + "and level=" + TC_Common::tostr(eLevelAllServer) + " " + "and set_name ='" + _mysqlConfig.escapeString(sNULL) + "' " + "and set_area ='" + _mysqlConfig.escapeString(sNULL) + "' " + "and set_group ='" + _mysqlConfig.escapeString(sNULL) + "' "; + + TC_Mysql::MysqlData res = _mysqlConfig.queryRecord(sSql); + + TLOGDEBUG("ConfigImp::loadConfigByHost sql:" << sSql << "|res.size:" << res.size() << endl); + + if(res.size() == 1) + { + sAllServerConfig = res[0]["config"]; + iAllConfigId = TC_Common::strto(res[0]["id"]); + } + + vector referenceIds; + + iRet = getReferenceIds(iAllConfigId,referenceIds); + + TLOGDEBUG("ConfigImp::loadConfigByHost referenceIds.size:" << referenceIds.size() << endl); + + if(iRet == 0) + { + for(size_t i = 0; i < referenceIds.size();i++) + { + int iRefId = referenceIds[i]; + string refConfig(""); + + iRet = loadConfigByPK(iRefId,refConfig); + if(iRet == 0 && (!refConfig.empty())) + { + if(config.empty()) + { + config += refConfig; + } + else + { + config += sSep + refConfig; + } + } + } + } + + //添加配置本身 + if(!sAllServerConfig.empty()) + { + if(config.empty()) + { + config += sAllServerConfig; + } + else + { + config += sSep + sAllServerConfig; + } + } + + + string sIpServerConfig = ""; + int iIpConfigId = 0; + + sSql = + "select id,config from t_config_files " + "where server_name = '" + _mysqlConfig.escapeString(appServerName) + "' " + "and filename='" + _mysqlConfig.escapeString(fileName) + "' " + "and host='" + _mysqlConfig.escapeString(host) + "' " + "and level=" + TC_Common::tostr(eLevelIpServer) + " " + "and set_name ='" + _mysqlConfig.escapeString(sNULL) + "' " + "and set_area ='" + _mysqlConfig.escapeString(sNULL) + "' " + "and set_group ='" + _mysqlConfig.escapeString(sNULL) + "' "; + + res = _mysqlConfig.queryRecord(sSql); + + TLOGDEBUG("ConfigImp::loadConfigByHost sql:" << sSql << "|res.size:" << res.size() << endl); + + if(res.size() == 1) + { + sIpServerConfig = res[0]["config"]; + iIpConfigId = TC_Common::strto(res[0]["id"]); + } + + iRet = getReferenceIds(iIpConfigId,referenceIds); + + TLOGDEBUG("ConfigImp::loadConfigByHost referenceIds.size:" << referenceIds.size() << endl); + + if(iRet == 0) + { + for(size_t i = 0; i < referenceIds.size(); i++) + { + int iRefId = referenceIds[i]; + string refConfig(""); + + iRet = loadConfigByPK(iRefId,refConfig); + if(iRet == 0 && (!refConfig.empty()) ) + { + if(config.empty()) + { + config += refConfig; + } + else + { + config += sSep + refConfig; + } + } + } + } + + //添加配置本身 + if(!sIpServerConfig.empty()) + { + if(config.empty()) + { + config += sIpServerConfig; + } + else + { + config += sSep + sIpServerConfig; + } + } + } + catch(TC_Mysql_Exception & ex) + { + config = ex.what(); + TLOGERROR("ConfigImp::loadConfigByHost exception:" << ex.what() << endl); + iRet = -1; + } + catch(...) + { + TLOGERROR("ConfigImp::loadConfigByHost unknown exception." << endl); + iRet = -1; + } + + return iRet; +} + +int ConfigImp::checkConfig(const std::string& appServerName, const std::string& fileName, const string &host, string &result, tars::TarsCurrentPtr current) +{ + TLOGDEBUG("ConfigImp::checkConfig appServerName:" << appServerName << "|fileName:" << fileName << "|host:" << host << endl); + + int ret = loadConfigByHost(appServerName, fileName, host, result, current); + if (ret != 0) + { + TLOGDEBUG("ConfigImp::checkConfig loadConfigByHost fail." << endl); + return -1; + } + + try + { + TC_Config conf; + conf.parseString(result); + } + catch(exception &ex) + { + TLOGDEBUG("ConfigImp::checkConfig exception:" << ex.what() << endl); + result = ex.what(); + return -1; + } + + return 0; +} + +///////////////////////////////////////////////private +int ConfigImp::loadConfigByPK(int iConfigId, string &sConfig) +{ + int iRet = 0 ; + //按照建立引用的先后返回 + try + { + string sSql = + "select config from t_config_files where id=" + TC_Common::tostr(iConfigId) +" order by id"; + + TC_Mysql::MysqlData res = _mysqlConfig.queryRecord(sSql); + + TLOGDEBUG("ConfigImp::loadConfigByPK sql:" << sSql << "|res.size:" << res.size() << endl); + + if(res.size() == 1) + { + sConfig = res[0]["config"]; + } + } + catch(TC_Mysql_Exception & ex) + { + sConfig = ex.what(); + TLOGERROR("ConfigImp::loadConfigByPK exception:" << ex.what() << endl); + return -1; + } + catch(...) + { + TLOGERROR("ConfigImp::loadConfigByPK unknown exception." << endl); + return -1; + } + + return iRet; +} + +int ConfigImp::loadRefConfigByPK(int iConfigId, const string& setdivision,string &sConfig) +{ + int iRet = 0 ; + //按照建立引用的先后返回 + try + { + string sSql = + "select server_name,filename,config from t_config_files where id=" + TC_Common::tostr(iConfigId) +" order by id"; + + TC_Mysql::MysqlData res = _mysqlConfig.queryRecord(sSql); + + TLOGDEBUG("ConfigImp::loadRefConfigByPK sql:" << sSql << "|res.size:" << res.size() << endl); + + if(res.size() == 1) + { + string sAppConfig = res[0]["config"]; + string sFileName = res[0]["filename"]; + string sServerName = res[0]["server_name"]; + + string sSetName(""); + string sSetArea(""); + string sSetGroup(""); + string sSetConfig(""); + + //查询该配置是否有set配置信息 + if(getSetInfo(sSetName,sSetArea,sSetGroup,setdivision)) + { + string sCondition; + sCondition += " and set_name='" +_mysqlConfig.escapeString(sSetName)+"' "; + sCondition += " and set_area='" +_mysqlConfig.escapeString(sSetArea)+"' "; + sCondition += " and set_group='" +_mysqlConfig.escapeString(sSetGroup)+"' "; + + string sSql = + "select config from t_config_files " + "where server_name = '" + _mysqlConfig.escapeString(sServerName) + "' " + "and filename='" + _mysqlConfig.escapeString(sFileName) + "' " + "and level=" + TC_Common::tostr(eLevelApp) + sCondition; + + TC_Mysql::MysqlData resSet = _mysqlConfig.queryRecord(sSql); + + TLOGDEBUG("ConfigImp::loadRefConfigByPK sql:" << sSql << "|resSet.size:" << resSet.size() << endl); + + if(resSet.size() == 1) + { + sSetConfig = resSet[0]["config"]; + } + } + + sConfig = mergeConfig(sAppConfig,sSetConfig); + } + } + catch(TC_Mysql_Exception & ex) + { + sConfig = ex.what(); + TLOGERROR("ConfigImp::loadRefConfigByPK exception: "< &referenceIds) +{ + int iRet = 0 ; + + referenceIds.clear(); + + string sSql = + "select reference_id from t_config_references where config_id=" + TC_Common::tostr(iConfigId); + + TLOGDEBUG("ConfigImp::getReferenceIds sql:" << sSql << endl); + + try + { + TC_Mysql::MysqlData res = _mysqlConfig.queryRecord(sSql); + + TLOGDEBUG("ConfigImp::getReferenceIds res.size:" << res.size() << endl); + + for(size_t i = 0 ; i < res.size(); i++) + { + int iRefId = TC_Common::strto(res[i]["reference_id"]); + referenceIds.push_back(iRefId); + } + } + catch(TC_Mysql_Exception & ex) + { + TLOGERROR("ConfigImp::getReferenceIds exception:" << ex.what() << endl); + return -1; + } + catch(...) + { + TLOGERROR("ConfigImp::getReferenceIds unknown exception" << endl); + return -1; + } + + return iRet; +} + + +int ConfigImp::loadAppConfig(const std::string& appName, const std::string& fileName, string &config, tars::TarsCurrentPtr current) +{ + TLOGDEBUG("ConfigImp::loadAppConfig appName:" << appName << "|fileName:" << fileName << endl); + + int iRet = 0 ; + config = ""; + + try + { + string sNULL; + //查公有配置 + string sSql = + "select id,config from t_config_files " + "where server_name = '" + _mysqlConfig.escapeString(appName) + "' " + "and filename='" + _mysqlConfig.escapeString(fileName) + "' " + "and level=" + TC_Common::tostr(eLevelApp) + " " + "and set_name ='" + _mysqlConfig.escapeString(sNULL) + "' " + "and set_area ='" + _mysqlConfig.escapeString(sNULL) + "' " + "and set_group ='" + _mysqlConfig.escapeString(sNULL) + "' "; + + TC_Mysql::MysqlData res = _mysqlConfig.queryRecord(sSql); + + TLOGDEBUG("ConfigImp::loadAppConfig sql:" << sSql << "|res.size:" << res.size() << endl); + + if(res.size() == 1) + { + config = res[0]["config"]; + } + } + catch(TC_Mysql_Exception & ex) + { + config = ex.what(); + TLOGERROR("ConfigImp::loadAppConfig exception:" << ex.what() << endl); + iRet = -1; + } + catch(...) + { + TLOGERROR("ConfigImp::loadAppConfig unknown exception." << endl); + iRet = -1; + } + + return iRet; + +} + +int ConfigImp::loadConfigByHost(const ConfigInfo & configInfo, string &config, tars::TarsCurrentPtr current) +{ + string sHost = configInfo.host.empty() ? current->getIp() : configInfo.host; + + TLOGDEBUG("ConfigImp::loadConfigByHost app:" << configInfo.appname << "|server:" << configInfo.servername << "|filename:" << configInfo.filename + << "|host:" << sHost << "|setdivision:" <(res[0]["id"]); + } + + //查服务配置的引用配置 + vector referenceIds; + iRet = getReferenceIds(iAllConfigId,referenceIds); + + TLOGDEBUG("ConfigImp::loadConfigByHost referenceIds.size:" << referenceIds.size() << endl); + + if(iRet == 0) + { + for(size_t i = 0; i < referenceIds.size();i++) + { + int iRefId = referenceIds[i]; + string refConfig(""); + + //此处获取的服务配置的引用配置信息 + iRet = loadRefConfigByPK(iRefId,configInfo.setdivision,refConfig); + if(iRet == 0 && (!refConfig.empty())) + { + sTemp = mergeConfig(sTemp,refConfig); + } + } + } + + //添加服务配置本身 + config = mergeConfig(sTemp,sAllServerConfig); + + sTemp.clear(); + + string sIpServerConfig(""); + int iIpConfigId = 0; + + //查看节点级配置 + sSql = + "select id,config from t_config_files " + "where server_name = '" + _mysqlConfig.escapeString(configInfo.appname + "." + configInfo.servername) + "' " + "and filename='" + _mysqlConfig.escapeString(configInfo.filename) + "' " + "and host='" + _mysqlConfig.escapeString(sHost) + "' " + "and level=" + TC_Common::tostr(eLevelIpServer); + + res = _mysqlConfig.queryRecord(sSql); + + TLOGDEBUG("ConfigImp::loadConfigByHost sql:" << sSql<< "|res.size:" << res.size() << endl); + + if(res.size() == 1) + { + sIpServerConfig = res[0]["config"]; + iIpConfigId = TC_Common::strto(res[0]["id"]); + } + + iRet = getReferenceIds(iIpConfigId, referenceIds); + + TLOGDEBUG("ConfigImp::loadConfigByHost referenceIds.size:" << referenceIds.size() << endl); + + if(iRet == 0) + { + string refAppConfig(""); + string refSetConfig(""); + for(size_t i = 0; i < referenceIds.size();i++) + { + int iRefId = referenceIds[i]; + string refConfig(""); + + //此处获取的节点配置的引用配置信息 + iRet = loadRefConfigByPK(iRefId,configInfo.setdivision,refConfig); + if(iRet == 0 && (!refConfig.empty())) + { + sTemp = mergeConfig(sTemp,refConfig); + } + } + } + + config = mergeConfig(config,mergeConfig(sTemp, sIpServerConfig)); + + } + catch(TC_Mysql_Exception & ex) + { + config = ex.what(); + TLOGERROR("ConfigImp::loadConfigByHost exception:" << ex.what() << endl); + iRet = -1; + } + catch(...) + { + TLOGERROR("ConfigImp::loadConfigByHost unknown exception" << endl); + iRet = -1; + } + + return iRet; +} + +int ConfigImp::loadAppConfigByInfo(const ConfigInfo & configInfo, string &config, tars::TarsCurrentPtr current) +{ + int iRet = 0; + config=""; + try + { + string sSql = + "select id,config from t_config_files " + "where server_name = '" + _mysqlConfig.escapeString(configInfo.appname) + "' " + "and filename='" + _mysqlConfig.escapeString(configInfo.filename) + "' " + "and level=" + TC_Common::tostr(eLevelApp); + + string sNULL(""); + string sCondition(""); + sCondition += " and set_name='" + _mysqlConfig.escapeString(sNULL) +"' "; + sCondition += " and set_area='" + _mysqlConfig.escapeString(sNULL) +"' "; + sCondition += " and set_group='" + _mysqlConfig.escapeString(sNULL) +"' "; + + //先获取app配置 + string sSqlAppNoSet = sSql + sCondition; + + TC_Mysql::MysqlData res = _mysqlConfig.queryRecord(sSqlAppNoSet); + + TLOGDEBUG("ConfigImp::loadAppConfigByInfo sSqlAppNoSet:" << sSqlAppNoSet << "|res.size:" << res.size() << endl); + + string sAppConfig(""); + + if(res.size() == 1) + { + sAppConfig = res[0]["config"]; + } + + //再获取app下有set信息的配置 + string sSetConfig; + if(!configInfo.setdivision.empty())//存在set信息 + { + string sSetName,sSetArea,sSetGroup; + + if(getSetInfo(sSetName,sSetArea,sSetGroup,configInfo.setdivision)) + { + string sCondition; + sCondition += " and set_name='" +_mysqlConfig.escapeString(sSetName)+"' "; + sCondition += " and set_area='" +_mysqlConfig.escapeString(sSetArea)+"' "; + sCondition += " and set_group='" +_mysqlConfig.escapeString(sSetGroup)+"' "; + + string sSqlSet = sSql + sCondition; + res = _mysqlConfig.queryRecord(sSqlSet); + + TLOGDEBUG("ConfigImp::loadAppConfigByInfo sSqlSet:" << sSqlSet << "|res.size:" << res.size() << endl); + + if(res.size() == 1) + { + sSetConfig = res[0]["config"]; + } + } + else + { + TLOGERROR("ConfigImp::loadAppConfigByInfo setdivision is invalid|configInfo.setdivision:" << configInfo.setdivision << endl); + return -1; + } + } + + config = mergeConfig(sAppConfig,sSetConfig); + + } + catch(TC_Mysql_Exception & ex) + { + config = ex.what(); + TLOGERROR("ConfigImp::loadAppConfigByInfo exception:" << ex.what() << endl); + iRet = -1; + } + catch(...) + { + TLOGERROR("ConfigImp::loadAppConfigByInfo unknown exception" << endl); + iRet = -1; + } + + return iRet; +} + +string ConfigImp::mergeConfig(const string& sLowConf,const string& sHighConf) +{ + + if(sLowConf.empty()) + { + return sHighConf; + } + else if(sHighConf.empty()) + { + return sLowConf; + } + else + { + return sLowConf + "\r\n\r\n" + sHighConf; + } +} + +//频率限制 +bool ConfigImp::IsLimited(const std::string & app, const std::string & server, const std::string & sIp,const string& sFile) +{ + const time_t INTERVAL = 1 * 60; + bool bLimited = false; + + { + ServerKey sKey = {app, server, sIp,sFile}; + + static TC_ThreadLock s_mutex; + + TC_ThreadLock::Lock lock(s_mutex); + + map >::iterator it = _loadConfigLimited.find(sKey); + if(it != _loadConfigLimited.end()) + { + ///1分钟内最多允许拉取10次 + if((TNOW - it->second.first) <= (INTERVAL*_interval)) + { + if(it->second.second <= _limitInterval) + { + it->second.second++; + } + else + { + bLimited = true; + TLOGERROR("ConfigImp::IsLimited app:" << app << "|server:" << server << "|sIp:" << sIp << "|sFile:" << sFile + << "|out of limit,now:" << it->second.second << "|limitInterval:" << _limitInterval << endl); + } + } + //已经超过1分钟了 + else + { + _loadConfigLimited.erase(sKey); + } + } + else + { + _loadConfigLimited.insert(std::make_pair(sKey,std::make_pair(TNOW,1))); + } + } + + return bLimited; +} + +int ConfigImp::ListAllConfigByInfo(const tars::GetConfigListInfo & configInfo, vector &vf, tars::TarsCurrentPtr current) +{ + CHECKLIMIT(configInfo.appname,configInfo.servername,current->getIp(),""); + + try + { + if(configInfo.bAppOnly) + { + //查ip对应配置 + string sSql = "select distinct filename from t_config_files " + "where server_name = '" + _mysqlConfig.escapeString(configInfo.appname) + "' " + "and level=" + TC_Common::tostr(eLevelApp); + + TLOGDEBUG("ConfigImp::ListAllConfigByInfo sql:" << sSql << endl); + + TC_Mysql::MysqlData res = _mysqlConfig.queryRecord(sSql); + + TLOGDEBUG("ConfigImp::ListAllConfigByInfo sql:" << sSql << "|res:" << res.size() << endl); + + for(unsigned i=0; i(eLevelIpServer); + } + + if(!configInfo.setdivision.empty()) + { + string sSetName,sSetArea,sSetGroup; + if(getSetInfo(sSetName,sSetArea,sSetGroup,configInfo.setdivision)) + { + sCondition += " and set_name='" +_mysqlConfig.escapeString(sSetName)+"' "; + sCondition += " and set_area='" +_mysqlConfig.escapeString(sSetArea)+"' "; + sCondition += " and set_group='" +_mysqlConfig.escapeString(sSetGroup)+"' "; + } + else + { + TLOGERROR("ConfigImp::ListAllConfigByInfo setdivision is invalid:" << configInfo.setdivision << endl); + return -1; + } + } + else//兼容没有set信息的业务 + { + string sNULL; + sCondition += " and set_name='" + _mysqlConfig.escapeString(sNULL) +"' "; + sCondition += " and set_area='" + _mysqlConfig.escapeString(sNULL) +"' "; + sCondition += " and set_group='" + _mysqlConfig.escapeString(sNULL) +"' "; + } + + sSql += sCondition; + + TLOGDEBUG("ConfigImp::ListAllConfigByInfo sql:" << sSql << endl); + + TC_Mysql::MysqlData res = _mysqlConfig.queryRecord(sSql); + + TLOGDEBUG("ConfigImp::ListAllConfigByInfo sql:" << sSql << "|res:" << res.size() << endl); + + for(unsigned i=0; i &vf,tars::TarsCurrentPtr current); + + /** + * 加载配置文件 + * param app :应用 + * param server: server名 + * param filename: 配置文件名 + * + * return : 配置文件内容 + */ + virtual int loadConfig(const std::string & app, const std::string & server, const std::string & filename, string &config, tars::TarsCurrentPtr current); + + /** + * 根据ip获取配置 + * @param appServerName + * @param filename + * @param host + * @param config + * + * @return int + */ + virtual int loadConfigByHost(const string &appServerName, const string &filename, const string &host, string &config, tars::TarsCurrentPtr current); + + /** + * + * @param appServerName + * @param filename + * @param host + * @param current + * + * @return int + */ + virtual int checkConfig(const string &appServerName, const string &filename, const string &host, string &result, tars::TarsCurrentPtr current); + + /** + * 获取配置文件列表 + * param configInfo ConfigInfo + * param vf: 配置文件名 + * + * return : 配置文件内容 + */ + virtual int ListConfigByInfo(const ConfigInfo& configInfo, vector &vf,tars::TarsCurrentPtr current); + + /** + * 加载配置文件 + * param configInfo ConfigInfo + * param config: 配置文件内容 + * + * return : + */ + virtual int loadConfigByInfo(const ConfigInfo & configInfo, string &config,tars::TarsCurrentPtr current); + + /** + * + * @param configInfo ConfigInfo + * + * @return int + */ + virtual int checkConfigByInfo(const ConfigInfo & configInfo, string &result,tars::TarsCurrentPtr current); + + /** + * 获取服务的所有配置文件列表, + * @param configInfo 支持拉取应用配置列表,服务配置列表,机器配置列表 + * @param[out] vf 获取到的文件名称列表 + * @return int 0: 成功, -1:失败 + **/ + virtual int ListAllConfigByInfo(const tars::GetConfigListInfo & configInfo, vector &vf, tars::TarsCurrentPtr current); + +protected: + + /** + * 加载本server的配置文件 + */ + void loadconf(); + +private: + + /** + * + * 查询configId对应的配置 + * + * @param iConfigId + * @param sConfig + * + * @return int 0,成功或者无此config,表示应用级配置 + * 2,表示set应用配置 + */ + int loadConfigByPK(int iConfigId, string &sConfig); + + /** + * + * 查询configId对应的配置信息,同时会查看该 + * + * @param iConfigId + * @param setdivision set分组信息 + * @param sConfig + * + * @return int 0,成功 + * + */ + int loadRefConfigByPK(int iConfigId, const string& setdivision,string &sConfig); + + /** + * + * 获取iConfigId对应的引用id列表 + * + * @param iConfigId + * @param referenceIds + * + * @return int + */ + int getReferenceIds(int iConfigId,vector &referenceIds); + + /** + * 获取应用级公共配置 + * @param appName 应用名称 + * @param fileName 文件名称 + * @out param 获取到的配置文件内容 + * + * @return int + */ + int loadAppConfig(const std::string& appName, const std::string& fileName, string &config, tars::TarsCurrentPtr current); + + /** + * 获取应用级公共配置 + * @param configInfo ConfigInfo + * @out param 获取到的配置文件内容 + * + * @return int + */ + int loadAppConfigByInfo(const ConfigInfo & configInfo, string &config, tars::TarsCurrentPtr current); + + /** + * 根据ip获取配置 + * @param configInfo ConfigInfo;configInfo中指定ip,如果没有则从current获取当前请求的ip + * @param config + * + * @return int + */ + int loadConfigByHost(const ConfigInfo & configInfo, string &config, tars::TarsCurrentPtr current); + + /** + * 获取set分组信息 + * @out param sSetName set名称 + * @out param sSetArea set地区名称 + * @out param sSetGroup set分组名称 + * @param sSetDivision set信息:sSetName.sSetArea.sSetGroup格式 + * + * @return bool set信息正确则返回true + */ + bool getSetInfo(string& sSetName,string& sSetArea,string& sSetGroup,const string& sSetDivision); + + /** + * 合并两个配置文件,如果有冲突项,则sHighConf优先级比sLowConf高 + * + * @param sLowConf 应用名称 + * @param sHighConf 应用名称 + * + * @ return string 合并的结果 + */ + string mergeConfig(const string& sLowConf,const string& sHighConf); + + /** + * 通过对app+server + ip + file进行限制加载配置文件的频率 + * + */ + bool IsLimited(const std::string & app, const std::string & server, const std::string & sIp,const string& sFile); + +protected: + TC_Mysql _mysqlConfig; + + static map > _loadConfigLimited; + + //时间间隔 + int _interval; + + ///每分钟限制个数 + int _limitInterval; +}; + +#endif + diff --git a/ConfigServer/ConfigServer.cpp b/ConfigServer/ConfigServer.cpp new file mode 100644 index 00000000..fcb276c5 --- /dev/null +++ b/ConfigServer/ConfigServer.cpp @@ -0,0 +1,32 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "ConfigServer.h" +#include "ConfigImp.h" + +void ConfigServer::initialize() +{ + //滚动日志也打印毫秒 + TarsRollLogger::getInstance()->logger()->modFlag(TC_DayLogger::HAS_MTIME); + + //增加对象 + addServant(ServerConfig::Application + "." + ServerConfig::ServerName + ".ConfigObj"); +} + +void ConfigServer::destroyApp() +{ +} + diff --git a/ConfigServer/ConfigServer.h b/ConfigServer/ConfigServer.h new file mode 100644 index 00000000..75b24f93 --- /dev/null +++ b/ConfigServer/ConfigServer.h @@ -0,0 +1,39 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __CONFIG_SERVER_H_ +#define __CONFIG_SERVER_H_ + +#include "servant/Application.h" + +using namespace tars; + +class ConfigServer : public Application +{ +protected: + /** + * 初始化, 进程只会调用一次 + */ + virtual void initialize(); + + /** + * 析构, 进程退出时会调用一次 + */ + virtual void destroyApp(); +}; + +#endif + diff --git a/ConfigServer/main.cpp b/ConfigServer/main.cpp new file mode 100644 index 00000000..133eb984 --- /dev/null +++ b/ConfigServer/main.cpp @@ -0,0 +1,42 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "ConfigServer.h" +#include + +using namespace tars; + +TC_Config * g_pconf; + +int main(int argc, char *argv[]) +{ + try + { + ConfigServer app; + g_pconf = & app.getConfig(); + app.main(argc, argv); + + app.waitForShutdown(); + } + catch(exception &ex) + { + cerr<< ex.what() << endl; + } + + return 0; +} + + diff --git a/LogServer/CMakeLists.txt b/LogServer/CMakeLists.txt new file mode 100644 index 00000000..a479a7c1 --- /dev/null +++ b/LogServer/CMakeLists.txt @@ -0,0 +1,7 @@ + +set(MODULE "tarslog") + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/deploy/${MODULE}/) + +complice_module(${MODULE}) + diff --git a/LogServer/LogImp.cpp b/LogServer/LogImp.cpp new file mode 100644 index 00000000..82515e71 --- /dev/null +++ b/LogServer/LogImp.cpp @@ -0,0 +1,433 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "LogImp.h" + +GlobeInfo g_globe; + +TC_DayLogger& GlobeInfo::makeDayLogger(const string &app, const string &server, const string &logname, const string &format,const string& ip) +{ + string sLogPath = _log_path + "/" + app + "/" + server + "/" + logname; + + TLOGDEBUG("GlobeInfo::makeDayLogger sLogPath:" << sLogPath << "|format:" << format << endl); + + DLOG << "GlobeInfo::makeDayLogger sLogPath:" << sLogPath << "|format:" << format << endl; + + TC_DayLogger *p = new TC_DayLogger(); + p->init(sLogPath, format); + p->setupThread(&_group); + + //所有标识都不要 + p->modFlag(0xffff, false); + + _loggers[logname][ip] = p; + + _formats[logname][ip] = format; + + return (*p); +} + +TC_DayLogger& GlobeInfo::makeDayLogger(const LogInfo & info, const string &logname, const string &format,const string& ip) +{ + string sLogPath = getRealLogName(info); + + //获取配置中的记录方式 + string sFormat = format; + string sLogType = info.sLogType; + string sKey = info.appname + "." +info.servername + "." + info.sFilename; + map::iterator it = _mLogType.find(sKey); + if(it != _mLogType.end()) + { + //服务端的配置优先级最高 + sLogType = it->second; + //使用规范格式 + sFormat = ""; + } + + TLOGDEBUG("GlobeInfo::makeDayLogger sLogPath:" << sLogPath << "|app:" << info.appname << "|server:" << info.servername << "|filename:" << info.sFilename + << "|format:" << format << "|setdivision:" << info.setdivision << "|bHasSufix:" << info.bHasSufix << "|bHasAppNamePrefix:" << info.bHasAppNamePrefix + << "|sConcatStr" << info.sConcatStr << "|sSepar" << info.sSepar << "|sLogType:" << sLogType << endl); + + DLOG << "GlobeInfo::makeDayLogger sLogPath:" << sLogPath << "|app:" << info.appname << "|server:" << info.servername << "|filename:" << info.sFilename + << "|format:" << format << "|setdivision:" << info.setdivision << "|bHasSufix:" << info.bHasSufix << "|bHasAppNamePrefix:" << info.bHasAppNamePrefix + << "|sConcatStr" << info.sConcatStr << "|sSepar" << info.sSepar << "|sLogType:" << sLogType <init(sLogPath, format,info.bHasSufix,info.sConcatStr,getTarsLogType(sFormat,sLogType)); + p->setSeparator(info.sSepar); + p->enableSqareWrapper(info.bHasSquareBracket); + + p->setupThread(&_group); + + //所有标识都不要 + p->modFlag(0xffff, false); + + _loggers[logname][ip] = p; + + _formats[logname][ip] = format; + return (*p); +} + +TarsLogTypePtr GlobeInfo::getTarsLogType(const string& sFormat,const string& sCutType) +{ + TarsLogTypePtr logTypePtr = NULL; + if(sCutType != "") + { + string sType = TC_Common::lower(sCutType); + string::size_type pos = string::npos; + if((pos = sType.find("day")) != string::npos) + { + int n = 1; + if(sType.substr(0,pos) != "" && TC_Common::isdigit(sType.substr(0,pos)) == true) + { + n = TC_Common::strto(sType.substr(0,pos)); + } + + string format = (sFormat=="") ? TarsLogByDay::FORMAT : sFormat; + logTypePtr = new TarsLogByDay(format,n); + } + else if((pos = sType.find("hour")) != string::npos) + { + int n = 1; + if(sType.substr(0,pos) != "" && TC_Common::isdigit(sType.substr(0,pos)) == true) + { + n = TC_Common::strto(sType.substr(0,pos)); + } + + string format = (sFormat=="") ? TarsLogByHour::FORMAT : sFormat; + logTypePtr = new TarsLogByHour(format,n); + } + else if((pos = sType.find("minute")) != string::npos) + { + int n = 10;//支持5,10分钟 + if(sType.substr(0,pos) != "" && TC_Common::isdigit(sType.substr(0,pos)) == true) + { + n = TC_Common::strto(sType.substr(0,pos)); + } + + string format = (sFormat=="") ? TarsLogByMinute::FORMAT : sFormat; + logTypePtr = new TarsLogByMinute(format,n); + } + } + + return logTypePtr; +} + +string GlobeInfo::getRealLogName(const LogInfo & info) +{ + string sRealLogname; + if(info.bHasAppNamePrefix) + { + sRealLogname = info.sFilename.empty() ? (info.appname +"." + info.servername) : \ + (info.appname +"." + info.servername + info.sConcatStr + info.sFilename); + } + else + { + sRealLogname = info.sFilename; + } + + string setDivision = getSetGoodFormat(info.setdivision); + + string sLogPath = _log_path + "/" + info.appname + "/" + setDivision + "/" + info.servername + "/" + sRealLogname; + + return sLogPath; +} + +string GlobeInfo::getLogName(const LogInfo & info) +{ + string sLogname = TC_Common::tostr(info.bHasSufix) + info.sConcatStr + TC_Common::tostr(info.bHasAppNamePrefix) + info.sConcatStr +\ + TC_Common::tostr(info.bHasSquareBracket) + info.sConcatStr + info.sSepar + info.sConcatStr +\ + info.setdivision + info.sConcatStr + info.appname + info.sConcatStr + info.servername + info.sConcatStr + info.sFilename + info.sConcatStr + info.sLogType; + + return sLogname; +} + +bool GlobeInfo::HasSameFormat(const string& logname,const string& format,string& ip) +{ + map::iterator itFormat = _formats[logname].begin(); + bool bHasFormat = false; //是否有创建过的format + for(; itFormat != _formats[logname].end(); itFormat++) + { + if(itFormat->second == format) //找到创建过的format + { + bHasFormat = true; + ip = itFormat->first; //为创建过相同format的节点ip + break; + } + } + + return bHasFormat; +} + +bool GlobeInfo::IsLoggerAttached(const string& logname,const string& sExcludeIp,const TC_DayLogger* pLogger) +{ + map::iterator itLogger = _loggers[logname].begin(); + bool bIsAttached = false; //是否有ip在用该logger实例 + + for(; itLogger != _loggers[logname].end(); itLogger++) + { + if(itLogger->first != sExcludeIp && itLogger->second == pLogger) + { + bIsAttached = true; + TLOGDEBUG("GlobeInfo::IsLoggerAttached first:" << itLogger->first<< endl); + break; + } + } + + return bIsAttached; +} + +TC_DayLogger& GlobeInfo::getLogger(const LogInfo & info,const string& ip) +{ + string format = info.sFormat; + if(binary_search(_vHourlist.begin(), _vHourlist.end(), (info.appname + "." + info.servername)) != false) + { + format = "%Y%m%d%H"; + } + + string setDivision = getSetGoodFormat(info.setdivision); + + if(!TC_File::isFileExistEx((_log_path + "/" + info.appname + "/" + setDivision + "/" + info.servername), S_IFDIR)) + { + TC_File::makeDirRecursive(_log_path + "/" + info.appname + "/" + setDivision + "/" + info.servername); + } + + string logname = getLogName(info); + + TLOGDEBUG("GlobeInfo::getLogger logname:" << logname << "|format:" << format << "|setDivision:" << setDivision << endl); + + Lock lock(*this); + + map >::iterator itLogName = _loggers.find(logname); + if( itLogName == _loggers.end()) //没有创建过的log + { + return makeDayLogger(info, logname, format, ip); + } + + map::iterator itIp = itLogName->second.find(ip); + if(itIp == itLogName->second.end()) //没有创建过的ip节点 + { + string sSameIp(""); + + if(HasSameFormat(logname,format,sSameIp)) //有创建过的format,把新的节点ip划分到同组 + { + _loggers[logname][ip] = _loggers[logname][sSameIp];//使用具有相同format的logger实例 + _formats[logname][ip] = format; + + return (*(_loggers[logname][ip])); + } + else //没有创建过该format,新建立一个logname下的format组 + { + return makeDayLogger(info, logname, format,ip); + } + + } + else //该logname下的这个ip节点创建过 + { + if(_formats[logname][ip] != format) //该ip节点的日志格式变化了 + { + string sSameIp(""); + TC_DayLogger* pOldLogger = _loggers[logname][ip]; + if(HasSameFormat(logname,format,sSameIp))//已经有该格式,归入同组 + { + _loggers[logname][ip] = _loggers[logname][sSameIp]; + _formats[logname][ip] = format; + + if(pOldLogger) //删除旧的loger + { + pOldLogger->unSetupThread(); + delete pOldLogger; + pOldLogger = NULL; + } + + return (*(_loggers[logname][ip])); + } + else + { + _loggers[logname][ip] = NULL; + _formats[logname][ip] = ""; + if(!IsLoggerAttached(logname,ip,pOldLogger))//可能有多个节点引用这个loger,这里需要判断 + { + pOldLogger->unSetupThread(); + delete pOldLogger; + pOldLogger = NULL; + } + + return makeDayLogger(info, logname, format,ip); + } + } + } + + //没有改变格式 + return (*(_loggers[logname][ip])); + +} + +TC_DayLogger& GlobeInfo::getLogger(const string &app, const string &server, const string &file, const string &sformat,const string& ip) +{ + if(!TC_File::isFileExistEx((_log_path + "/" + app + "/" + server), S_IFDIR)) + { + TC_File::makeDirRecursive(_log_path + "/" + app + "/" + server); + } + + string format = sformat; + if(binary_search(_vHourlist.begin(),_vHourlist.end(),(app + "." + server)) != false) + { + format = "%Y%m%d%H"; + } + + string logname = file.empty() ? (app + "." + server) : (app + "." + server + "_" + file); + + TLOGDEBUG("GlobeInfo::getLogger logname:" << logname << "|format:" << format << endl); + + Lock lock(*this); + + map >::iterator itLogName = _loggers.find(logname); + if( itLogName == _loggers.end()) //没有创建过的log + { + return makeDayLogger(app, server, logname, format,ip); + } + + map::iterator itIp = itLogName->second.find(ip); + if(itIp == itLogName->second.end()) //没有创建过的ip节点 + { + string sSameIp(""); + if(HasSameFormat(logname,format,sSameIp)) //有创建过的format,把新的节点ip划分到同组 + { + _loggers[logname][ip] = _loggers[logname][sSameIp];//使用具有相同format的logger实例 + _formats[logname][ip] = format; + + return (*(_loggers[logname][ip])); + } + else //没有创建过该format,新建立一个logname下的format组 + { + return makeDayLogger(app, server, logname, format,ip); + } + + } + else //该logname下的这个ip节点创建过 + { + if(_formats[logname][ip] != format) //该ip节点的日志格式变化了 + { + string sSameIp(""); + TC_DayLogger* pOldLogger = _loggers[logname][ip]; + if(HasSameFormat(logname,format,sSameIp))//已经有该格式,归入同组 + { + _loggers[logname][ip] = _loggers[logname][sSameIp]; + _formats[logname][ip] = format; + + if(pOldLogger) //删除旧的loger + { + pOldLogger->unSetupThread(); + delete pOldLogger; + pOldLogger = NULL; + } + + return (*(_loggers[logname][ip])); + } + else + { + _loggers[logname][ip] = NULL; + _formats[logname][ip] = ""; + if(!IsLoggerAttached(logname,ip,pOldLogger))//可能有多个节点引用这个loger,这里需要判断 + { + pOldLogger->unSetupThread(); + delete pOldLogger; + pOldLogger = NULL; + } + + return makeDayLogger(app, server, logname, format,ip); + } + } + } + + //没有改变格式 + return (*(_loggers[logname][ip])); +} + +string GlobeInfo::getSetGoodFormat(const string& sSetDivision) +{ + vector vtSetDivisions = TC_Common::sepstr(sSetDivision,"."); + if(vtSetDivisions.size() != 3) + { + return ""; + } + else + { + if(vtSetDivisions[2] == "*") + { + return string(vtSetDivisions[0] + vtSetDivisions[1]); + } + else + { + return string(vtSetDivisions[0] + vtSetDivisions[1] + vtSetDivisions[2]); + } + } +} + + +void GlobeInfo::update(const vector &vHourlist, const map &mLogType) +{ + Lock lock(*this); + + _vHourlist = vHourlist; + + _mLogType = mLogType; +} + +////////////////////////////////////////// +// +void LogImp::initialize() +{ + +} + +void LogImp::logger(const string &app, const string &server, const string &file, const string &format, const vector &buffer, tars::TarsCurrentPtr current) +{ + TC_DayLogger &dl = g_globe.getLogger(app, server, file, format,current->getIp()); + + //记录日志 + for(size_t i = 0; i < buffer.size(); i++) + { + if(g_globe._bIpPrefix) + { + dl.any() << current->getIp() << "|" << buffer[i]; + } + else + { + dl.any() << buffer[i]; + } + } +} + +void LogImp::loggerbyInfo(const LogInfo & info,const vector & buffer,tars::TarsCurrentPtr current) +{ + TC_DayLogger &dl = g_globe.getLogger(info,current->getIp()); + + //记录日志 + for(size_t i = 0; i < buffer.size(); i++) + { + if(g_globe._bIpPrefix) + { + dl.any() << current->getIp() << info.sSepar << buffer[i]; + } + else + { + dl.any() << buffer[i]; + } + } +} diff --git a/LogServer/LogImp.h b/LogServer/LogImp.h new file mode 100644 index 00000000..83348ef6 --- /dev/null +++ b/LogServer/LogImp.h @@ -0,0 +1,222 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __LOG_IMP_H_ +#define __LOG_IMP_H_ + +#include "servant/LogF.h" +#include "util/tc_common.h" +#include "util/tc_file.h" +#include "util/tc_logger.h" +#include "util/tc_monitor.h" +#include "LogServer.h" + +using namespace tars; + +/** + * 全局信息 + */ +struct GlobeInfo : public TC_ThreadLock +{ +public: + /** + * 获取按天日志 + * @param app + * @param server + * @param file + * @param format + * @param ip 服务所在节点ip + * + * @return TC_DayLogger& + */ + TC_DayLogger& getLogger(const string &app, const string &server, const string &file, const string &format,const string& ip); + + /** + * 获取按天日志 + * @param info 详情参看LogInfo + * @param ip 服务所在节点ip + * + * @return TC_DayLogger& + */ + TC_DayLogger& getLogger(const LogInfo & info,const string& ip); + + /** + * 更新_vHourlist和_mLogType配置 + */ + void update(const vector &vHourlist, const map &mLogType); + +protected: + /** + * 生成按天日志 + * @param info 详情参看LogInfo + * @param logname + * @param format + * @param ip 服务所在节点ip + * + * @return TC_DayLogger& + */ + TC_DayLogger& makeDayLogger(const LogInfo & info, const string &logname, const string &format,const string& ip); + + /** + * 生成按天日志 + * @param app + * @param server + * @param logname + * @param format + * @param ip 服务所在节点ip + * + * @return TC_DayLogger& + */ + TC_DayLogger& makeDayLogger(const string &app, const string &server, const string &logname, const string &format,const string& ip); + + /** + * 判断相应的logname下是否有指定的format + * @param logname 由file.empty() ? (app + "." + server) : (app + "." + server + "_" + file)方式组成 + * @param format + * @param[out] ip 如果有指定的format存在,则返回该format对应的节点ip + * + * @return bool + */ + bool HasSameFormat(const string& logname,const string& format,string& ip); + + /** + * 判断在logname下,除了节点sExcludeIp外,是否还有其它节点在使用pLoger指定的logger实例 + * @param logname + * @param sExcludeIp + * @param pLogger + * + * @return bool + */ + bool IsLoggerAttached(const string& logname,const string& sExcludeIp,const TC_DayLogger* pLoger); + +private: + /** + * 获取set完整格式 + * @param sSetDivision set分组信息,例如:mtt.s.1 mtt.s.* + * + * @return 规整后的格式,例如:mtt.s.* 去掉"*"符号,返回mtts;mtts1则原样返回 + */ + string getSetGoodFormat(const string& sSetDivision); + + /** + * 从LogInfo中获取相关信息得到标识一个logger对象的字符串 + * @param info + */ + string getLogName(const LogInfo & info); + + /** + * 从LogInfo中获取日志文件名称,包括路径名在内 + * @param info + */ + string getRealLogName(const LogInfo & info); + + TarsLogTypePtr getTarsLogType(const string& sFormat, const string& sCutType); + +public: + /** + * 写日志线程 + */ + TC_LoggerThreadGroup _group; + + /** + * 写日志路径 + */ + string _log_path; + + /** + * logger对象:logname,ip,logger + */ + map > _loggers; + + /** + * logger格式:logname,ip,format + */ + map > _formats; + + /** + * 按小时记录的配置 + */ + vector _vHourlist; + + /** + * 按时间方式配置 + * key:日志文件全名: appname.servername.filename + * value:时间格式字符串:hour,2hour,5minute,10minute + */ + map _mLogType; + + /** + *是否打印客户端ip + */ + bool _bIpPrefix; + +}; + +extern GlobeInfo g_globe; + +/** + * log实现 + */ +class LogImp : public Log +{ +public: + /** + * + */ + LogImp(){}; + + /** + * + */ + ~LogImp(){}; + + /** + * 初始化 + * + * @return int + */ + virtual void initialize(); + + /** + * 退出 + */ + virtual void destroy() {}; + + /** + * 输出日志信息到指定文件 + * @param app 业务名称 + * @param server 服务名称 + * @param file 日志文件名称 + * @param format 日志输出格式 + * @param buffer 日志内容 + * + * + */ + void logger(const string &app, const string &server, const string &file, const string &format, const vector &buffer, tars::TarsCurrentPtr current); + /** + * 获取数据 + * @param info + * @param buffer + * + */ + void loggerbyInfo(const LogInfo & info,const vector & buffer,tars::TarsCurrentPtr current); + +private: + +}; + +#endif + diff --git a/LogServer/LogServer.cpp b/LogServer/LogServer.cpp new file mode 100644 index 00000000..69a7ae82 --- /dev/null +++ b/LogServer/LogServer.cpp @@ -0,0 +1,116 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "LogServer.h" +#include "util/tc_logger.h" +#include "LogImp.h" + +void LogServer::initialize() +{ + string s; + loadLogFormat("","",s); + + //日志路径 + g_globe._log_path = _conf["/tars/log"]; + + //启动写线程 + g_globe._group.start(TC_Common::strto(_conf["/tars/log"])); + + string prefix = TC_Common::lower(_conf.get("/tars/log","true")); + g_globe._bIpPrefix = (prefix == "true") ? true : false; + + //增加对象 + addServant(ServerConfig::Application + "." + ServerConfig::ServerName +".LogObj"); + + TARS_ADD_ADMIN_CMD_NORMAL("reloadLogFormat", LogServer::loadLogFormat); +} + +bool LogServer::loadLogFormat(const string& command, const string& params, string& result) +{ + TLOGDEBUG("LogServer::loadLogFormat command:" << command << "|params:" << params << endl); + + try + { + TC_Config conf; + + conf.parseFile(ServerConfig::ConfigFile); + + vector vHourlist; + + map mLogType; + + try + { + string sHour = conf["/tars/log/format"]; + + vHourlist = TC_Common::sepstr(sHour,"|;,"); + + sort(vHourlist.begin(),vHourlist.end()); + + unique(vHourlist.begin(),vHourlist.end()); + + result = "loadLogFormat succ:" + sHour; + + TLOGDEBUG("LogServer::loadLogFormat result:" << result << endl); + + DLOG<< "LogServer::loadLogFormat result:" << result << endl; + + //hour=app.server.file|app2.server2.file2 + map mType; + if(conf.getDomainMap("/tars/log/logtype", mType)) + { + map::iterator it = mType.begin(); + while(it != mType.end()) + { + vector vList = TC_Common::sepstr(it->second,"|;,"); + for(size_t i = 0;i < vList.size();i++) + { + //app.server.file = hour + mLogType[vList[i]] = it->first; + + TLOGDEBUG("LogServer::loadLogFormat " << vList[i] << "|" << it->first << endl); + + DLOG<<"LogServer::loadLogFormat " << vList[i] << "|" << it->first << endl; + } + it++; + } + } + + g_globe.update(vHourlist, mLogType); + + } + catch(exception& e) + { + result += e.what(); + TLOGERROR("LogServer::loadLogFormat command:" << command << "|params:" << params << "|result:" << result << endl); + } + + return true; + } + catch(exception &e) + { + result += e.what(); + TLOGERROR("LogServer::loadLogFormat command:" << command << "|params:" << params << "|result:" << result << endl); + } + + return false; +} + +void LogServer::destroyApp() +{ + TLOGDEBUG("LogServer::destroyApp ok" << endl); +} + diff --git a/LogServer/LogServer.h b/LogServer/LogServer.h new file mode 100644 index 00000000..450981df --- /dev/null +++ b/LogServer/LogServer.h @@ -0,0 +1,43 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __LOG_SERVER_H_ +#define __LOG_SERVER_H_ + +#include "servant/Application.h" + +using namespace tars; + +class LogServer : public Application +{ +protected: + /** + * 初始化, 进程会调用一次 + */ + virtual void initialize(); + + /** + * 析够, 进程退出时会调用一次 + */ + virtual void destroyApp(); + +private: + + bool loadLogFormat(const string& command, const string& params, string& result); +}; + +#endif + diff --git a/LogServer/main.cpp b/LogServer/main.cpp new file mode 100644 index 00000000..cee3f209 --- /dev/null +++ b/LogServer/main.cpp @@ -0,0 +1,39 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "LogServer.h" +#include + +using namespace tars; + +LogServer g_app; + +int main(int argc, char *argv[]) +{ + try + { + g_app.main(argc, argv); + g_app.waitForShutdown(); + } + catch(exception &ex) + { + cout << ex.what() << endl; + } + + return 0; +} + + diff --git a/NodeServer/Activator.cpp b/NodeServer/Activator.cpp new file mode 100644 index 00000000..d3004f1e --- /dev/null +++ b/NodeServer/Activator.cpp @@ -0,0 +1,465 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include +#include "Activator.h" +#include "NodeServer.h" + +static pid_t *childpid = NULL; /* ptr to array allocated at run-time */ +#define SHELL "/bin/sh" + +pid_t Activator::activate(const string& strExePath, const string& strPwdPath, const string& strRollLogPath, const vector& vOptions, vector& vEnvs) +{ + TC_ThreadLock::Lock lock(*this); + addActivatingRecord(); + if (isActivatingLimited() == true) + { + TLOGERROR("Activator::activate The server " << strExePath << " activating is limited! it will not auto start until after " + TC_Common::tostr(_punishInterval) + " seconds" << endl); + } + + if (strExePath.empty()) + { + throw runtime_error("The server executable path is empty."); + } + + if (TC_File::isFileExistEx(strExePath) && !TC_File::canExecutable(strExePath)) + { + TC_File::setExecutable(strExePath, true); + } + vector vArgs; + vArgs.push_back(strExePath); + vArgs.insert(vArgs.end(), vOptions.begin(), vOptions.end()); + + TLOGDEBUG("Activator::activate activating server [exepath: " << strExePath << ", args: " << TC_Common::tostr(vArgs) << "]" << endl); + + int argc = static_cast(vArgs.size()); + char **argv = static_cast(malloc((argc + 1) * sizeof(char *))); + int i = 0; + for (vector::const_iterator p = vArgs.begin(); p != vArgs.end(); ++p, ++i) + { + assert(i < argc); + argv[i] = strdup(p->c_str()); + } + assert(i == argc); + argv[argc] = 0; + + const char *pwdCStr = strPwdPath.c_str(); + + pid_t pid = fork(); + if (pid == -1) + { + TLOGDEBUG("Activator::activate "<< strPwdPath << "|fork child process catch exception|errno=" << errno << endl); + throw runtime_error("fork child process catch exception"); + } + + if (pid == 0) + { + int maxFd = static_cast(sysconf(_SC_OPEN_MAX)); + for (int fd = 3; fd < maxFd; ++fd) + { + close(fd); + } + + //server stdcout 日志在滚动日志显示 + if (_redirectPath != "") + { + TC_File::makeDirRecursive(TC_File::extractFilePath(_redirectPath)); + if ((freopen64(_redirectPath.c_str(), "ab", stdout)) != NULL && (freopen64(_redirectPath.c_str(), "ab", stderr)) != NULL) + { + cout << argv[0] << " redirect stdout and stderr to " << _redirectPath << endl; + } + else + { + //重定向失败 直接退出 + exit(0); + //cout << argv[0]<<" cannot redirect stdout and stderr to log file" << _redirectPath << "|errno=" < mResult; + if (doScript(strServerId, strStartScript, strResult, mResult) == false) + { + throw runtime_error("run script file " + strStartScript + " error :" + strResult); + } + + pid_t pid = -1; + if (!strMonitorScript.empty() && TC_File::isFileExistEx(strMonitorScript)) + { + string s; + mResult.clear(); + if (doScript(strServerId, strMonitorScript, s, mResult) == false) + { + throw runtime_error("run script " + strMonitorScript + " error :" + s); + } + } + + return pid; +} + +int Activator::deactivate(int pid) +{ + if (pid != 0) + { + return sendSignal(pid, SIGKILL); + } + + return -1; +} + +int Activator::deactivateAndGenerateCore(int pid) +{ + if (pid != 0) + { + return sendSignal(pid, SIGABRT); + } + + return -1; +} + +int Activator::sendSignal(int pid, int signal) const +{ + assert(pid); + int ret = ::kill(static_cast(pid), signal); + if (ret != 0 && errno != ESRCH) + { + TLOGERROR("Activator::activate send signal " << signal << " to pid " << pid << " catch exception|" << errno << endl); + return -1; + } + + return ret; +} + +bool Activator::isActivatingLimited() +{ + unsigned uLen = _activingRecord.size(); + + //惩罚时间段内禁止启动 + if (_limited == true && uLen > 0 && TNOW - _activingRecord[uLen - 1] < _punishInterval) + { + return true; + } + + return false; +} +void Activator::addActivatingRecord() +{ + time_t tNow = TNOW; + unsigned uLen = _activingRecord.size(); + + if (uLen > 0) + { + if (tNow - _activingRecord[uLen - 1] < _timeInterval) + { + _curCount++; + } + + //完成惩罚时间,自动解除惩罚 + if (_limited == true && tNow - _activingRecord[uLen - 1] > _punishInterval * 1.5) + { + _curCount = 0; + _limited = false; + _activingRecord.clear(); + } + + if (_curCount > _maxCount) + { + _limited = true; + } + } + _activingRecord.push_back(tNow); +} + +bool Activator::doScript(const string& strServerId, const string& strScript, string& strResult, map& mResult, const string& sEndMark) +{ + TLOGINFO("Activator::activate doScript " << strScript << " begin----" << endl); + + if (!TC_File::isFileExistEx(strScript)) + { + strResult = "The script file: " + strScript + " is not exist"; + return false; + } + + string sRealEndMark = sEndMark; + if (sRealEndMark == "") + { + sRealEndMark = "end-" + TC_File::extractFileName(strScript); + } + + TLOGINFO("Activator::activate doScript " << strScript << " endMark----" << sRealEndMark << endl); + + if (!TC_File::canExecutable(strScript)) + { + TC_File::setExecutable(strScript, true); + } + + string sRedirect = ""; + if (_redirectPath != "") + { + sRedirect = " 2>&1 >>" + _redirectPath; + } + + string sCmd = strScript + sRedirect + " " + strServerId + " &"; + FILE *fp = popen2(sCmd.c_str(), "r"); + if (fp == NULL) + { + strResult = "popen script file: " + strScript + " error "; + return false; + } + + //使文件变成非阻塞方式访问 + int flags; + if ((flags = fcntl(fileno(fp), F_GETFL, 0)) < 0) + { + strResult = "fcntl get error.script file: " + strScript; + fflush(fp); + pclose2(fp); + return false; + } + flags |= O_NONBLOCK; + if (fcntl(fileno(fp), F_SETFL, flags) < 0) + { + strResult = "fcntl set error.script file: " + strScript; + fflush(fp); + pclose2(fp); + + return false; + } + //strResult = ""; + + int c; + time_t tNow = TNOW; + while (TNOW - 2 < tNow) + { + usleep(200000); + while ((c = fgetc(fp)) != EOF) + { + strResult += (char)c; + } + if (sRealEndMark == "" || strResult.find(sRealEndMark) != string::npos) + { + TLOGINFO("Activator::doScript "<< sCmd << "|sEndMark " << sRealEndMark << " finded|" << strResult << endl); + break; + } + } + + strResult = TC_Common::replace(strResult, "\n", "\r\n"); + LOG->info() << "Activator::doScript "<< sCmd << " result:" << strResult << endl; + + fflush(fp); + pclose2(fp); + + mResult = parseScriptResult(strServerId, strResult); + return true; +} + +map Activator::parseScriptResult(const string& strServerId, const string& strResult) +{ + map mResult; + vector vResult = TC_Common::sepstr(strResult, "\n"); + for (unsigned i = 0; i < vResult.size(); i++) + { + string::size_type pos = vResult[i].find('='); + if (pos != string::npos) + { + string sName = vResult[i].substr(0, pos); + string sValue = vResult[i].substr(pos + 1); + sName = TC_Common::lower(TC_Common::trim(sName)); + sValue = TC_Common::trim(sValue); + mResult[sName] = sValue; + if (sName == "notify") + { + g_app.reportServer(strServerId, sValue); + } + } + } + + return mResult; +} + +FILE* Activator::popen2(const char *cmdstring, const char *type) +{ + int i, pfd[2]; + pid_t pid; + FILE *fp; + /*only allow "r" or "w" */ + if ((type[0] != 'r' && type[0] != 'w') || type[1] != 0) + { + errno = EINVAL; /* required by POSIX.2 */ + return (NULL); + } + int maxfd = static_cast(sysconf(_SC_OPEN_MAX)); + if (childpid == NULL) + { /* first time through */ + /* allocate zeroed out array for child pids */ + childpid = new pid_t[maxfd]; + memset(childpid, 0, sizeof(pid_t) * maxfd); + //char** envArray = new char*[envCount]; + if (childpid == NULL) + { + return (NULL); + } + } + + if (pipe(pfd) < 0) + { + return (NULL); /* errno set by pipe() */ + } + + if ((pid = fork()) < 0) + { + return (NULL); /* errno set by fork() */ + } + else if (pid == 0) + { /* child */ + if (*type == 'r') + { + close(pfd[0]); + dup2(pfd[1], STDOUT_FILENO); + dup2(pfd[1], STDERR_FILENO); + close(pfd[1]); + } + else + { + close(pfd[1]); + dup2(pfd[0], STDIN_FILENO); + close(pfd[0]); + } + /* close all descriptors opened in parent process*/ + for (i = 3; i < maxfd; i++) + { + if (i != pfd[0] && i != pfd[1]) + { + close(i); + } + } + execl(SHELL, "sh", "-c", cmdstring, (char *)0); + _exit(127); + } + /* parent */ + if (*type == 'r') + { + close(pfd[1]); + if ((fp = fdopen(pfd[0], type)) == NULL) + { + return (NULL); + } + } + else + { + close(pfd[0]); + if ((fp = fdopen(pfd[1], type)) == NULL) + { + return (NULL); + } + } + childpid[fileno(fp)] = pid; /* remember child pid for this fd */ + return (fp); +} + +int Activator::pclose2(FILE *fp) +{ + int fd, stat; + pid_t pid; + + if (childpid == NULL) + { + return (-1); /* popen() has never been called */ + } + fd = fileno(fp); + if ((pid = childpid[fd]) == 0) + { + return (-1); /* fp wasn't opened by popen() */ + } + childpid[fd] = 0; + if (fclose(fp) == EOF) + { + return (-1); + } + + while (waitpid(pid, &stat, 0) < 0) + { + if (errno != EINTR) + { + return (-1); /* error other than EINTR from waitpid() */ + } + } + return (stat); /* return child's termination status */ +} diff --git a/NodeServer/Activator.h b/NodeServer/Activator.h new file mode 100644 index 00000000..abe3b3ee --- /dev/null +++ b/NodeServer/Activator.h @@ -0,0 +1,209 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __ACTIVATOR_H_ +#define __ACTIVATOR_H_ +#include "Node.h" +#include +#include "util/tc_file.h" +#include "util/tc_monitor.h" +#include + +using namespace tars; +using namespace std; +//////////////////////////////////////////////////// +// + +//用来标志脚本结束 +///////////////////////////////////////////////////////// +// 环境变量 +struct EnvVal : std::unary_function +{ + string operator()(const std::string& value) + { + string::size_type pos = value.find("="); + if(pos == string::npos || pos >= value.size() - 1) + { + return value; + } + + string v = value.substr(pos + 1); + assert(v.size()); + + string::size_type start = 0; + string::size_type finish; + + //宏替换 + while((start = v.find("$", start)) != string::npos && start < v.size() - 1) + { + string var; + if(v[start + 1] == '{') + { + finish = v.find("}"); + if(finish == string::npos) + { + break; + } + var = v.substr(start + 2, finish - start - 2); + } + else + { + finish = start + 1; + while((isalnum(v[finish]) || v[finish] == '_') && finish < v.size()) + { + ++finish; + } + var = v.substr(start + 1, finish - start - 1); + --finish; + } + + char* p = getenv(var.c_str()); + string str = p ? string(p) : ""; + + v.replace(start, finish - start + 1, str); + + start += str.size(); + } + + //此处需要马上设置,否则以上宏替换中获取的环境变量为空 + setenv((value.substr(0, pos)).c_str(), v.c_str(), true); + + return value.substr(0, pos) + "=" + v; + } +}; + +class Activator : public TC_ThreadLock, public TC_HandleBase +{ +public: + /** + * 构造服务 + * iTimeInterval秒内最多进行iMaxCount次启动。 达到最大启动次数仍失败后iPunishInterval秒重试启动一次 + * @param iTimeInterval + * @param iMaxCount + * @param iPunishInterval 惩罚时间间隔 + * + */ + Activator(int iTimeInterval,int iMaxCount,int iPunishInterval) + : _maxCount(iMaxCount) + , _timeInterval(iTimeInterval) + , _punishInterval(iPunishInterval) + , _termSignal(false) + , _redirectPath("") + { + clearRunntimeData(); + }; + + ~Activator() + { + }; + + /** + * 启动服务 + * + * @param strExePath 可执行文件路径 + * @param strPwdPath 当前路径 + * @param strRollLogPath 日志路径 + * @param vOptions 启动参数 + * @param vEnvs 环境变量 + * @return pid_t 生成子进程id + * + */ + pid_t activate(const string& strExePath, const string& strPwdPath, const string &strRollLogPath, const vector& vOptions, vector& vEnvs); + + /** + * 脚本启动服务 + * + * @param sServerId 服务id + * @param strStartScript 脚本路径 + * @param strMonitorScript 脚本路径 + * @param sResult 执行结果 + * @return pid_t 生成子进程id + * + */ + pid_t activate(const string &strServerId, const string& strStartScript, const string &strMonitorScript, string &strResult); + + /** + * 停止服务 + * + * @param pid 进程id + * @return int 0 成功 其它失败 + */ + int deactivate( int pid ); + + /** + * 停止服务 并生成core文件 + * + * @param pid 进程id + * @return int 0 成功 其它失败 + */ + int deactivateAndGenerateCore( int pid ); + + /** + * 发送信号 + * + * @param pid 进程id + * @param signal 信号 + * @return int 0 成功 其它失败 + */ + int sendSignal( int pid, int signal ) const; +public: + + bool isActivatingLimited (); //启动限制,用来防止问题服务不断重启影响其它服务 + + void addActivatingRecord(); + + //运行脚本 + bool doScript(const string &sServerId, const string &strScript, string &strResult, map &mResult,const string &sEndMark = ""); + + map parseScriptResult(const string &strServerId,const string &strResult); + + void setRedirectPath(const string& sRedirectpath) {_redirectPath = sRedirectpath;} + + void clearRunntimeData() + { + _activingRecord.clear(); + _limited = false; + _curCount = 0; + }; + + void setLimitInfo(int iTimeInterval,int iMaxCount,int iPunishInterval) + { + _timeInterval = iTimeInterval; + _maxCount = iMaxCount; + _punishInterval = iPunishInterval; + clearRunntimeData(); + } + +private: + int pclose2(FILE *fp); + FILE* popen2(const char *cmdstring, const char *type); + +private: + vector _activingRecord; //运行时 + bool _limited; //是否启动受限,运行时 + int _curCount; //当前启动次数,运行时 + int _maxCount; //最大启动次数,配置 + int _timeInterval; //时间,单位分钟,配置 + int _punishInterval; //惩罚受限时间间隔,单位分钟,配置 + +private: + bool _termSignal; //非tars服务脚本运行超时停止信号 + string _redirectPath; //标准输出和错误输出重定向目录 +}; + +typedef TC_AutoPtr ActivatorPtr; +#endif + diff --git a/NodeServer/BatchPatchThread.cpp b/NodeServer/BatchPatchThread.cpp new file mode 100644 index 00000000..a1e94325 --- /dev/null +++ b/NodeServer/BatchPatchThread.cpp @@ -0,0 +1,222 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "util/tc_md5.h" +#include "BatchPatchThread.h" +#include "ServerFactory.h" +#include "CommandPatch.h" +#include "NodeRollLogger.h" +#include "util.h" + +using namespace tars; + +BatchPatch::BatchPatch() +{ + +} + +BatchPatch::~BatchPatch() +{ + terminate(); +} + +void BatchPatch::start(int iNum) +{ + for (int i = 0; i < iNum; i++) + { + BatchPatchThread * t = new BatchPatchThread(this); + t->setPath(_downloadPath); + t->start(); + + _runners.push_back(t); + } +} + +void BatchPatch::terminate() +{ + for (size_t i = 0; i < _runners.size(); ++i) + { + if(_runners[i]->isAlive()) + { + _runners[i]->terminate(); + } + } + + for (size_t i = 0; i < _runners.size(); ++i) + { + if(_runners[i]->isAlive()) + { + _runners[i]->getThreadControl().join(); + } + } + +} + +void BatchPatch::push_back(const tars::PatchRequest & request, ServerObjectPtr serverPtr) +{ + { + TC_ThreadLock::Lock LockQueue(_queueMutex); + + if (_patchIng.count(request.appname + request.servername) == 1) + { + std::string sException = "reduplicate patch request:" + request.version + "," + request.user; + + NODE_LOG("patchPro")->debug() << FILE_FUN<< request.appname + "." + request.servername << "|" << sException << endl; + throw TC_Exception(sException); + } + + if (!serverPtr) + { + NODE_LOG("patchPro")->error() << FILE_FUN<< "server null " <& item) +{ + TC_ThreadLock::Lock LockQueue(_queueMutex); + + bool bRet=false; + + bRet=_patchQueue.pop_front(item); + + if(bRet) + { + _patchIng.erase(item.first.appname+item.first.servername); + } + + return bRet; +} + +void BatchPatch::timedWait(int millsecond) +{ + TC_ThreadLock::Lock lock(_queueMutex); + + _queueMutex.timedWait(millsecond); +} + +BatchPatchThread::BatchPatchThread(BatchPatch * patch) : _batchPatch(patch) +{ + _shutDown = false; +} + +BatchPatchThread::~BatchPatchThread() +{ + terminate(); +} + +void BatchPatchThread::terminate() +{ + _shutDown = true; + + if (isAlive()) + { + getThreadControl().join(); + } +} + +void BatchPatchThread::doPatchRequest(const tars::PatchRequest & request, ServerObjectPtr server) +{ + NODE_LOG("patchPro")->debug() << FILE_FUN + << request.appname + "." + request.servername + "_" + request.nodename << "|" + << request.groupname << "|" + << request.version << "|" + << request.user << "|" + << request.servertype << "|" + << request.patchobj << "|" + << request.md5 << "|" + << request.ostype << endl; + + + //设置发布状态 + try + { + std::string sError; + + if (!server) + { + NODE_LOG("patchPro")->error() <debug() <error() << FILE_FUN<< request.appname + "." + request.servername << "|" << request.md5 << "|canExecute error:" << sError << endl; + return ; + } + + if (command.execute(sError) == 0) + { + NODE_LOG("patchPro")->debug() <error() <error() << FILE_FUN<< request.appname + "." + request.servername << "|" << request.md5 << "|Exception:" << e.what() << endl; + } + catch (...) + { + NODE_LOG("patchPro")->error() < item; + if (_batchPatch->pop_front(item)) + { + if (!(item.second)) + { + NODE_LOG("patchPro")->error() <timedWait(2000); + } + } + catch (exception& e) + { + NODE_LOG("patchPro")->error()<error()<& item); + + /** + * 设置下载暂存目录 + */ + void setPath(const std::string & sDownloadPath) + { + _downloadPath = sDownloadPath; + } +private: + tars::TC_ThreadLock _queueMutex; + + TC_ThreadQueue > _patchQueue; + + std::set _patchIng; + + std::vector _runners; + + std::string _downloadPath; +}; + + +class BatchPatchThread : public TC_Thread +{ +public: + BatchPatchThread(BatchPatch * patch); + + ~BatchPatchThread(); + + virtual void run(); + + void terminate(); + +public: + /** + * 设置下载暂存目录 + */ + void setPath(const std::string & sDownloadPath) + { + _downloadPath = sDownloadPath; + } + + /** + * 执行发布单个请求 + */ + void doPatchRequest(const tars::PatchRequest & request, ServerObjectPtr server); + +protected: + BatchPatch * _batchPatch; + + std::string _downloadPath; //文件下载目录 + +protected: + bool _shutDown; +}; + +#endif diff --git a/NodeServer/CMakeLists.txt b/NodeServer/CMakeLists.txt new file mode 100644 index 00000000..c7028c9b --- /dev/null +++ b/NodeServer/CMakeLists.txt @@ -0,0 +1,14 @@ + +include_directories(${PROJECT_SOURCE_DIR}/patchclient) + +link_libraries(patch) + +set(MODULE "tarsnode") + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/deploy/${MODULE}/bin) + +#complice_module(${MODULE} "Node.tars") +complice_module(${MODULE}) + +#tarsnode依赖patch的客户端 +add_dependencies(${MODULE} patch) diff --git a/NodeServer/CommandAddFile.h b/NodeServer/CommandAddFile.h new file mode 100644 index 00000000..562a4280 --- /dev/null +++ b/NodeServer/CommandAddFile.h @@ -0,0 +1,194 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __ADDFILE_COMMAND_H_ +#define __ADDFILE_COMMAND_H_ + +#include "ServerCommand.h" + +/** + *自config服务下载文件 + * + */ +class CommandAddFile : public ServerCommand +{ + +public: + CommandAddFile(const ServerObjectPtr &pServerObjectPtr,const string &sFile,bool bByNode = false); + ExeStatus canExecute(string &sResult); + int execute(string &sResult); +private: + int getScriptFile(string &sResult); + bool _byNode; + string _file; + string _serverId; + ServerDescriptor _desc; + StatExChangePtr _statExChange; + ServerObjectPtr _serverObjectPtr; +}; + +////////////////////////////////////////////////////////////// +// +inline CommandAddFile::CommandAddFile(const ServerObjectPtr &pServerObjectPtr,const string &sFile,bool bByNode) +:_byNode(bByNode) +,_file(sFile) +,_serverObjectPtr(pServerObjectPtr) +{ + _desc = _serverObjectPtr->getServerDescriptor(); + _serverId = _serverObjectPtr->getServerId(); +} + +////////////////////////////////////////////////////////////////////////////// +// +inline ServerCommand::ExeStatus CommandAddFile::canExecute(string &sResult) +{ + + TC_ThreadRecLock::Lock lock( *_serverObjectPtr ); + + TLOGDEBUG("CommandAddFile::canExecute "<<_desc.application<< "." << _desc.serverName << " beging addFilesing------"<< endl); + ServerObject::InternalServerState eState = _serverObjectPtr->getInternalState(); + + if(_desc.application == "" || _desc.serverName == "" ) + { + TLOGERROR("CommandAddFile::canExecute app or server name is empty"<getExePath()+"/"+_file; + } + _file = TC_File::simplifyDirectory(TC_Common::trim(_file)); + + string sFilePath = TC_File::extractFilePath(_file); + + string sFileName = TC_File::extractFileName(_file); + //创建目录 + if(!TC_File::makeDirRecursive(sFilePath ) ) + { + + TLOGERROR("CommandAddFile::execute cannot create dir:"<isScriptFile(sFileName) == true) + { + bRet = getScriptFile(sResult); + } + else + { + TarsRemoteConfig tTarsRemoteConfig; + tTarsRemoteConfig.setConfigInfo(Application::getCommunicator(), ServerConfig::Config,_desc.application, _desc.serverName, sFilePath,_desc.setId); +// tTarsRemoteConfig.setConfigInfo(ServerConfig::Config,_desc.application, _desc.serverName, sFilePath,_desc.setId); + bRet = tTarsRemoteConfig.addConfig(sFileName,sResult); + g_app.reportServer(_serverObjectPtr->getServerId(),sResult); + } + return bRet; + } + catch(exception &e) + { + TLOGERROR("CommandAddFile::execute get file: "<<_file<<" from configServer fail."<stringToProxy(ServerConfig::Config); + string sStream; + int ret; + if(_desc.setId.empty()) + { + ret = pPtr->loadConfig(_desc.application, _desc.serverName, sFileName, sStream); + } + else + { + struct ConfigInfo confInfo; + confInfo.appname = _desc.application; + confInfo.servername = _desc.serverName; + confInfo.filename = sFileName; + confInfo.setdivision = _desc.setId; + ret = pPtr->loadConfigByInfo(confInfo,sStream); + } + + if (ret != 0) + { + sResult = FILE_FUN_STR+"[fail] get remote file :" + sFileName; + TLOGERROR(sResult<decodeMacro(sStream); + string sTem; + string::size_type pos = sStream.find('\n'); + while(pos != string::npos) + { + sTem = sTem + TC_Common::trim(sStream.substr(0,pos)," \r\t") +"\n"; + sStream = sStream.substr(pos+1); + pos = sStream.find('\n'); + } + sStream = sTem + sStream; + string sEndMark = "echo 'end-"+sFileName+"'"; + if(sStream.find(sEndMark) == string::npos) + { + sStream = sStream + "\n"+sEndMark ; //tarsnode 生成的脚本都以 'echo 'end filename'' 结束 + } + if(TC_File::isFileExist(_file) && TC_File::load2str(_file) != sStream) + { + TC_File::copyFile(_file,_file+".bak"); + } + ofstream out(_file.c_str()); + if(!out.good()) + { + TLOGERROR("CommandAddFile::getScriptFile cannot create file: "<<(_file + " erro:"+ strerror(errno))<getServerId(),sResult); + TLOGDEBUG(sResult<getServerDescriptor(); +} +////////////////////////////////////////////////////////////// +// +inline ServerCommand::ExeStatus CommandDestroy::canExecute(string &sResult) +{ + TC_ThreadRecLock::Lock lock( *_serverObjectPtr ); + + NODE_LOG("destroyServer")->debug()<getInternalState(); + + if (eState != ServerObject::Inactive) + { + sResult = FILE_FUN_STR+"server state is not Inactive. the curent state is " + _serverObjectPtr->toStringState( eState ); + NODE_LOG("destroyServer")->debug()<getServerDir(); + string sServerId = _serverObjectPtr->getServerId(); + + //删除服务日志目录 + string sLogPath = _serverObjectPtr->getLogPath(); + if (sLogPath.empty()) + {//使用默认路径 + sLogPath = "/usr/local/app/tars/app_log/"; + } + + vector vtServerNames = TC_Common::sepstr(sServerId,"."); + if (vtServerNames.size() != 2) + { + NODE_LOG("destroyServer")->error() <push_back(sLogPath); + + //异步删除data下文件或者子目录 + if(TC_File::isFileExistEx(sServerDir, S_IFDIR)) + { + g_RemoveLogThread->push_back(sServerDir); + NODE_LOG("destroyServer")->error()<error()<error()<error()<& macro, const string& value); + + /** + * 获取server配置文件 + * @return int + */ + void getRemoteConf(); + +private: + bool _byNode; + NodeInfo _nodeInfo; + ServerDescriptor _desc; + ServerObjectPtr _serverObjectPtr; + StatExChangePtr _statExChange; + +private: + string _serverDir; //服务数据目录 + string _confPath; //服务配置文件目录 + string _confFile; //服务配置文件目录 _strConfPath/conf + string _exePath; //服务可执行程序目录。可个性设定,一般为_strServerDir/bin + string _exeFile; //一般为_strExePath+_strServerName 可个性指定 + string _logPath; //服务日志目录 + string _libPath; //动态库目录 一般为_desc.basePath/lib + string _serverType; //服务类型 +private: + string _startScript; //启动脚本 + string _stopScript; //停止脚本 + string _monitorScript; //监控脚本 +}; + +////////////////////////////////////////////////////////////// +// +CommandLoad::CommandLoad(const ServerObjectPtr& pServerObjectPtr, const NodeInfo& tNodeInfo, bool bByNode) +: _byNode(bByNode) +, _nodeInfo(tNodeInfo) +, _serverObjectPtr(pServerObjectPtr) +{ + _desc = _serverObjectPtr->getServerDescriptor(); +} + +////////////////////////////////////////////////////////////// +// +inline ServerCommand::ExeStatus CommandLoad::canExecute(string& sResult) +{ + + TC_ThreadRecLock::Lock lock(*_serverObjectPtr); + + TLOGDEBUG("CommandLoad::canExecute " << _desc.application << "." << _desc.serverName << "|" << _desc.setId << "| beging loaded------|" << endl); + + ServerObject::InternalServerState eState = _serverObjectPtr->getInternalState(); + + if (_desc.application == "" || _desc.serverName == "") + { + TLOGDEBUG("CommandLoad::canExecute app or server name is empty"<< endl); + return DIS_EXECUTABLE; + } + + if (_serverObjectPtr->toStringState(eState).find("ing") != string::npos && eState != ServerObject::Activating) + { + TLOGDEBUG("CommandLoad::canExecute cannot loading the config, the server state is "<<_serverObjectPtr->toStringState(eState)<< endl); + return DIS_EXECUTABLE; + } + + //设当前状态为正在loading + _statExChange = new StatExChange(_serverObjectPtr, ServerObject::Loading, eState); + + return EXECUTABLE; +} + + +////////////////////////////////////////////////////////////// +// +inline int CommandLoad::execute(string& sResult) +{ + //初始化服务目录信息 + _serverDir = TC_Common::trim(_desc.basePath); + _exePath = TC_Common::trim(_desc.exePath); + _serverType = TC_Common::lower(TC_Common::trim(_desc.serverType)); + + //若serverDir不合法采用默认路径 + if (_serverDir.empty() || TC_File::isAbsolute(_serverDir) == false) + { + _serverDir = TC_File::simplifyDirectory(_nodeInfo.dataDir + "/" + _desc.application + "." + _desc.serverName); + } + + //若exePath不合法采用默认路径 + //注意java服务启动方式特殊 可执行文件为java 须特殊处理 + if (_exePath.empty()) + { + _exePath = _serverDir + "/bin/"; + if (_serverType == "tars_java") + { + _exeFile = "java"; + } + else + { + _exeFile = _exePath + _desc.serverName; + } + } + else if (TC_File::isAbsolute(_exePath) == false) + { + //此时_desc.exePath为手工指定,手工指定时_desc.exePath为文件 所以路径要扣除可执行文件名 + //而且可执行文件名可以不等于_strServerName 用来用同一可执行文件,不同配置启动多个服务 + _exeFile = _serverDir + "/bin/" + _exePath; + _exePath = TC_File::extractFilePath(_exeFile); + } + else + { + //此时_desc.exePath为手工指定,手工指定时_desc.exePath为文件 所以路径要扣除可执行文件名 + //而且可执行文件名可以不等于_strServerName 用来用同一可执行文件,不同配置启动多个服务 + _exeFile = _desc.exePath; + _exePath = _serverType == "tars_java" ? _serverDir + "/bin/" : TC_File::extractFilePath(_desc.exePath); + } + + _exeFile = TC_File::simplifyDirectory(_exeFile); + + _exePath = TC_File::simplifyDirectory(_exePath) + "/"; + + //启动脚本处理 + _startScript = TC_Common::trim(_desc.startScript); + if (!_startScript.empty() && TC_File::isAbsolute(_startScript) == false) + { + _startScript = _exePath + _startScript; + } + + //停止脚本处理 + _stopScript = TC_Common::trim(_desc.stopScript); + if (!_stopScript.empty() && TC_File::isAbsolute(_stopScript) == false) + { + _stopScript = _exePath + _stopScript; + } + + //监控脚本处理 + _monitorScript = TC_Common::trim(_desc.monitorScript); + if (!_monitorScript.empty() && TC_File::isAbsolute(_monitorScript) == false) + { + _monitorScript = _exePath + _monitorScript; + } + + _startScript = TC_File::simplifyDirectory(_startScript); + _stopScript = TC_File::simplifyDirectory(_stopScript); + _monitorScript = TC_File::simplifyDirectory(_monitorScript); + + //创建配置lib文件目录 + _libPath = _nodeInfo.dataDir + "/lib/"; + + //获取服务框架配置文件 + _confPath = _serverDir + "/conf/"; + + _confFile = _confPath + _desc.application + "." + _desc.serverName + ".config.conf"; + + TLOGDEBUG("CommandLoad::execute"<< _serverType << "," + << "exe_path=" << _exePath << "," + << "exe_file=" << _exeFile << "," + << "start_script=" << _startScript << "," + << "stop_script=" << _stopScript << "," + << "monitor_script="<< _monitorScript<< "," + << "config_file=" << _confFile << endl); + + //创建目录 + if (!TC_File::makeDirRecursive(_exePath)) + { + + TLOGERROR("CommandLoad::execute cannot create dir: "<<(_exePath + " erro:" + strerror(errno))< m; + + m["node"] = ServerConfig::Application + "." + ServerConfig::ServerName + ".ServerObj@" + g_app.getAdapterEndpoint("ServerAdapter").toString(); + tConf.insertDomainParam("/tars/application/server", m, true); + m.clear(); + + map::const_reverse_iterator itAdapters; + for (itAdapters = _desc.adapters.rbegin(); itAdapters != _desc.adapters.rend(); itAdapters++) + { + TLOGINFO("CommandLoad::updateConfigFile get adapter " << itAdapters->first << endl); + if (LOG->IsNeedLog(TarsRollLogger::INFO_LOG)) + { + _desc.display(LOG->info()); + } + + if (itAdapters->first == "") + { + continue; + } + + tEp.parse(itAdapters->second.endpoint); + m["endpoint"] = tEp.toString(); + m["allow"] = itAdapters->second.allowIp; + m["queuecap"] = TC_Common::tostr(itAdapters->second.queuecap); + m["queuetimeout"] = TC_Common::tostr(itAdapters->second.queuetimeout); + m["maxconns"] = TC_Common::tostr(itAdapters->second.maxConnections); + m["threads"] = TC_Common::tostr(itAdapters->second.threadNum); + m["servant"] = TC_Common::tostr(itAdapters->second.servant); + m["protocol"] = itAdapters->second.protocol == "" ? "tars" : itAdapters->second.protocol; + m["handlegroup"] = itAdapters->second.handlegroup == "" ? itAdapters->first : itAdapters->second.handlegroup; + + tConf.insertDomainParam("/tars/application/server/" + itAdapters->first, m, true); + } + + //获取本地socket + TC_Endpoint tLocalEndpoint; + uint16_t p = tEp.getPort(); + if (p == 0) + { + try + { + //原始配置文件中有admin端口了, 直接使用 + TC_Config conf; + conf.parseFile(_confFile); + TC_Endpoint ep; + ep.parse(conf.get("/tars/application/server")); + p = ep.getPort(); + } + catch (exception& ex) + { + //随机分配一个端口 + TC_Socket t; + t.createSocket(); + t.bind("127.0.0.1", 0); + string d; + t.getSockName(d, p); + t.close(); + } + + } + + tLocalEndpoint.setPort(p); + tLocalEndpoint.setHost("127.0.0.1"); + tLocalEndpoint.setTcp(true); + tLocalEndpoint.setTimeout(3000); + + //需要宏替换部分配置 + TC_Config tConfMacro; + map mMacro; + mMacro.clear(); + mMacro["locator"] = Application::getCommunicator()->getProperty("locator"); + + //>>修改成从主控获取locator地址 + vector activeEp; + vector inactiveEp; + QueryFPrx queryProxy = AdminProxy::getInstance()->getQueryProxy(); + int iRet = 0; + try + { + iRet = queryProxy->findObjectById4All(AdminProxy::getInstance()->getQueryProxyName(), activeEp, inactiveEp); + TLOGDEBUG("CommandLoad::updateConfigFile " << _serverObjectPtr->getServerId() << "|iRet|" << iRet << "|" << activeEp.size() << "|" << inactiveEp.size() << endl); + } + catch (exception& e) + { //获取主控地址异常时,仍使用node中的locator + TLOGERROR("CommandLoad::updateConfigFile:get registry locator excetpion:" << e.what() << "|" << _serverObjectPtr->getServerId() << endl); + iRet = -1; + } + catch (...) + { + TLOGERROR("CommandLoad::updateConfigFile:get registry locator unknown exception|" << _serverObjectPtr->getServerId() << endl); + iRet = -1; + } + + if (iRet == 0 && activeEp.size() > 0) + { + string sLocator = AdminProxy::getInstance()->getQueryProxyName() + "@"; + for (size_t i = 0; i < activeEp.size(); ++i) + { + string sSingleAddr = "tcp -h " + activeEp[i].host + " -p " + TC_Common::tostr(activeEp[i].port); + sLocator += sSingleAddr + ":"; + } + sLocator = sLocator.substr(0, sLocator.length() - 1); + mMacro["locator"] = sLocator; + TLOGDEBUG("CommandLoad::updateConfigFile:" << _serverObjectPtr->getServerId() << "|locator|" << sLocator << endl); + } + + mMacro["modulename"] = _desc.application + "." + _desc.serverName; + mMacro["app"] = _desc.application; + mMacro["server"] = _desc.serverName; + mMacro["serverid"] = _serverObjectPtr->getServerId(); + mMacro["localip"] = g_app.getAdapterEndpoint("ServerAdapter").getHost(); + mMacro["exe"] = TC_File::simplifyDirectory(_exeFile); + mMacro["basepath"] = TC_File::simplifyDirectory(_exePath) + "/"; + mMacro["datapath"] = TC_File::simplifyDirectory(_serverDir) + "/data/"; + mMacro["logpath"] = ServerConfig::LogPath; + mMacro["local"] = tLocalEndpoint.toString(); + + mMacro["mainclass"] = "com.qq." + TC_Common::lower(_desc.application) + "." + TC_Common::lower(_desc.serverName) + "." + _desc.serverName; + mMacro["config-center-port"] = TC_Common::tostr(_desc.configCenterPort); + + mMacro["setdivision"] = _desc.setId; + + mMacro["enableset"] = "n"; + if (!mMacro["setdivision"].empty()) + { + mMacro["enableset"] = "y"; + } + else + { + mMacro["setdivision"] = "NULL"; + } + + mMacro["asyncthread"] = TC_Common::tostr(_desc.asyncThreadNum); + + //创建目录 + TC_File::makeDirRecursive(mMacro["basepath"]); + TC_File::makeDirRecursive(mMacro["datapath"]); + TC_File::makeDirRecursive(_logPath + "/" + _desc.application + "/" + _desc.serverName + "/"); + + //合并两类配置 + _serverObjectPtr->setMacro(mMacro); + + string strProfile = _serverObjectPtr->decodeMacro(_desc.profile); + tConfMacro.parseString(strProfile); + tConf.joinConfig(tConfMacro, true); + + string sStream = TC_Common::replace(tConf.tostr(), "\\s", " "); + string sConfigFileBak = _confFile + ".bak"; + if (TC_File::isFileExist(_confFile) && TC_File::load2str(_confFile) != sStream) + { + TC_File::copyFile(_confFile, sConfigFileBak); + } + + ofstream configfile(_confFile.c_str()); + if (!configfile.good()) + { + TLOGERROR("CommandLoad::updateConfigFile cannot create configuration file: " << _confFile << endl); + return -1; + } + + configfile << sStream; + configfile.close(); + + _logPath = tConf.get("/tars/application/server", ""); + + _serverObjectPtr->setJvmParams(tConf.get("/tars/application/server", "")); + _serverObjectPtr->setMainClass(tConf.get("/tars/application/server", "")); + _serverObjectPtr->setClassPath(tConf.get("/tars/application/server", "")); + _serverObjectPtr->setEnv(tConf.get("/tars/application/server", "")); + _serverObjectPtr->setHeartTimeout(TC_Common::strto(tConf.get("/tars/application/server", ""))); + + _serverObjectPtr->setRedirectPath(tConf.get("/tars/application/", "")); + + _serverObjectPtr->setBackupFileNames(tConf.get("/tars/application/server", "classes/autoconf")); + + bool bEn = (TC_Common::lower(tConf.get("/tars/application/server", "y")) == "y") ? true : false; + + _serverObjectPtr->setEnSynState(bEn); + + _serverObjectPtr->setExeFile(_exeFile); + _serverObjectPtr->setConfigFile(_confFile); + _serverObjectPtr->setExePath(_exePath); + _serverObjectPtr->setLogPath(_logPath); + _serverObjectPtr->setLibPath(_libPath); + _serverObjectPtr->setServerDir(_serverDir); + _serverObjectPtr->setNodeInfo(_nodeInfo); + + //取合并后配置 + TC_Endpoint localEp; + localEp.parse(tConf.get("/tars/application/server")); + _serverObjectPtr->setLocalEndpoint(localEp); + + _serverObjectPtr->setServerType(_serverType); + _serverObjectPtr->setScript(_startScript, _stopScript, _monitorScript); + _serverObjectPtr->setLoaded(true); + + return 0; + } + catch (exception& e) + { + sResult = e.what(); + TLOGERROR("CommandLoad::updateConfigFile "<getServerId() == "tars.tarsconfig") + { + return ; + } + string sResult; + try + { + ConfigPrx pPtr = Application::getCommunicator()->stringToProxy(ServerConfig::Config); + vector vf; + int ret; + + if (_desc.setId.empty()) + { + ret = pPtr->ListConfig(_desc.application, _desc.serverName, vf); + } + else + { + struct ConfigInfo confInfo; + confInfo.appname = _desc.application; + confInfo.servername = _desc.serverName; + confInfo.setdivision = _desc.setId; + ret = pPtr->ListConfigByInfo(confInfo, vf); + } + + if (ret != 0) + { + TLOGERROR("CommandLoad::getRemoteConf [fail] get remote file list"<< endl); + g_app.reportServer(_serverObjectPtr->getServerId(), sResult); + } + + for (unsigned i = 0; i < vf.size(); i++) + { + //脚本拉取 需要宏替换 + if (_serverObjectPtr->isScriptFile(vf[i]) == true) + { + _serverObjectPtr->getRemoteScript(vf[i]); + continue; + } + + //非tars服务配置文件需要node拉取 tars服务配置服务启动时自己拉取 + if (_serverObjectPtr->isTarsServer() != true) + { + + TarsRemoteConfig tTarsRemoteConfig; + tTarsRemoteConfig.setConfigInfo(Application::getCommunicator(),ServerConfig::Config,_desc.application, _desc.serverName, _exePath,_desc.setId); + tTarsRemoteConfig.addConfig(vf[i], sResult); + g_app.reportServer(_serverObjectPtr->getServerId(), sResult); + } + } + } + catch (exception& e) + { + TLOGERROR("CommandLoad::getRemoteConf " << e.what() << endl); + } +} + +#endif diff --git a/NodeServer/CommandNotify.h b/NodeServer/CommandNotify.h new file mode 100644 index 00000000..2572de51 --- /dev/null +++ b/NodeServer/CommandNotify.h @@ -0,0 +1,100 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __NOTIFY_COMMAND_H_ +#define __NOTIFY_COMMAND_H_ + +#include "ServerCommand.h" +#include "NodeRollLogger.h" + +/** + * 通知服务 + * + */ +class CommandNotify : public ServerCommand +{ +public: + CommandNotify(const ServerObjectPtr &pServerObjectPtr,const string &sMsg,bool bByNode = false); + + ExeStatus canExecute(string &sResult); + + int execute(string &sResult); + +private: + bool _byNode; + string _msg; + ServerDescriptor _desc; + ServerObjectPtr _serverObjectPtr; +}; + +////////////////////////////////////////////////////////////// +// +inline CommandNotify::CommandNotify(const ServerObjectPtr &pServerObjectPtr,const string &sMsg,bool bByNode) +:_byNode(bByNode) +,_msg(sMsg) +,_serverObjectPtr(pServerObjectPtr) +{ + _desc = _serverObjectPtr->getServerDescriptor(); +} +////////////////////////////////////////////////////////////// +// +inline ServerCommand::ExeStatus CommandNotify::canExecute(string &sResult) +{ + NODE_LOG("notify")->debug()<getInternalState(); + + if ( eState == ServerObject::Inactive) + { + sResult = "server state is Inactive. "; + NODE_LOG("notify")->debug()<debug()<getLocalEndpoint().toString(); + pAdminPrx = Application::getCommunicator()->stringToProxy(sAdminPrx); + sResult = pAdminPrx->notify(_msg); + } + catch (exception& e) + { + NODE_LOG("notify")->debug()< 0) + { + _serverObjectPtr->setPatchPercent((int)(pos*100.0/fi.size)); + } + } + +private: + ServerObjectPtr _serverObjectPtr; +}; + +////////////////////////////////////////////////////////////// +// +inline CommandPatch::CommandPatch(const ServerObjectPtr & server, const std::string & sDownloadPath, const tars::PatchRequest & request) +: _serverObjectPtr(server), _patchRequest(request) +{ + _localTgzBasePath = sDownloadPath + "/BatchPatchingLoad"; + _localExtractBasePath = sDownloadPath + "/BatchPatching"; +} + +inline string CommandPatch::getOsType() +{ + string defaultOs = g_pconf->get("/tars/node", "suse"); + string ret = defaultOs; + + vector vKey = g_pconf->getDomainKey("/tars/node/os_pattern"); + NODE_LOG("patchPro")->debug() << FILE_FUN<< vKey.size() << endl; + for(size_t i = 0; i < vKey.size(); i++) + { + string key = vKey[i]; + string paths = g_pconf->get("/tars/node/os_pattern<" + key + ">", ""); + NODE_LOG("patchPro")->debug() < vPath = TC_Common::sepstr(paths,":"); + vector::iterator it = vPath.begin(); + for(; it != vPath.end(); it ++) + { + string path = *it; + if(TC_File::isFileExist(path)) + { + ret = key; + NODE_LOG("patchPro")->debug() << FILE_FUN<< path << " is exist, ret:" << ret << endl; + return ret; + } + else + { + NODE_LOG("patchPro")->debug() << FILE_FUN<< path << " not exist" << endl; + } + } + } + + return ret; +} + +inline bool CommandPatch::checkOsType() +{ + string checkStr = g_pconf->get("/tars/node", "n"); + if(checkStr == "Y" || checkStr == "y" || checkStr == "yes" || checkStr == "true") + { + return true; + } + else + { + return false; + } +} + + +inline ServerCommand::ExeStatus CommandPatch::canExecute(string & sResult) +{ + ServerObject::InternalServerState eState = _serverObjectPtr->getLastState(); + + ServerObject::InternalServerState eCurrentState =_serverObjectPtr->getInternalState(); + + NODE_LOG("patchPro")->debug()<< FILE_FUN <<_patchRequest.appname+"."+_patchRequest.servername<<"|sResult:"<toStringState(eCurrentState)<<"|last state :"<< _serverObjectPtr->toStringState(eState)<< endl; + + _statExChange = new StatExChange(_serverObjectPtr, ServerObject::BatchPatching, eState); + + _serverObjectPtr->setPatchVersion(_patchRequest.version); + _serverObjectPtr->setPatchPercent(0); + _serverObjectPtr->setPatchResult(""); + + return EXECUTABLE; +} + +inline int CommandPatch::updatePatchResult(string & sResult) +{ + try + { + NODE_LOG("patchPro")->debug() <getRegistryProxy(); + if (!proxy) + { + sResult = "patch succ but update version and user fault, get registry proxy fail"; + + NODE_LOG("patchPro")->error() <updatePatchResult(patch); + NODE_LOG("patchPro")->debug() <error() <error() <debug() <debug() <debug() <debug() <error() <stringToProxy(_patchRequest.patchobj); + proxy->tars_timeout(60000); + + int downloadRet = SingleFileDownloader::download(proxy, sRemoteTgzFile, dtask.sLocalTgzFile, eventPtr, sResult); + if(downloadRet != 0) + { + //返回码错开一下 + iRet = downloadRet - 100; + returned = true; + } + } + catch (std::exception & ex) + { + sResult = "download from patch exception," + string(ex.what()); + iRet = -3; + NODE_LOG("patchPro")->error() <error() <debug() <error() <error() <error() <error() <error() <getConfigFile()); + string packageFormat= conf.get("/tars/application/server","war"); + string cmd,sLocalTgzFile_bak; + if (_serverObjectPtr->getServerType() == "tars_java") //如果是tars_java,使用war 方法 + { + //NODE_LOG("patchPro")->error() <<"tgz file name"< files; + tars::TC_File::listDirectory(sLocalExtractPach, files, true); + if(files.empty()) + { + sResult = cmd + ",error!"; + NODE_LOG("patchPro")->error() <debug() << FILE_FUN << "unzip:" << cmd <debug() <error() << FILE_FUN << sResult << endl; + iRet = -7; + } + } + } + + //对于tars_nodejs需要先删除exepath下的文件 + if (iRet == 0) + { + if (_serverObjectPtr->getServerType() == "tars_nodejs") + { + if(TC_File::removeFile(_serverObjectPtr->getExePath(),true) != 0 || !TC_File::makeDirRecursive(_serverObjectPtr->getExePath())) + { + iRet = -8; //iRetCode = EM_ITEM_PERMISSION; + NODE_LOG("patchPro")->error() <getExePath()<<"|"<getServerType() == "tars_nodejs") + { + TC_File::copyFile(sLocalExtractPach + "/" + sServerName+ "/" + sServerName, _serverObjectPtr->getExePath(), true); + } + else + { + //如果出错,这里会抛异常 + if(packageFormat!="jar") + { + TC_File::copyFile(sLocalExtractPach + "/" + sServerName, _serverObjectPtr->getExePath(), true); + } + else + { + // TC_File::copyFile( sLocalTgzFile_bak , _serverObjectPtr->getExePath(), true); + string cpCmd =" cp -f "+sLocalTgzFile_bak+" "+_serverObjectPtr->getExePath()+";"; + system(cpCmd.c_str()); + } + } + + //设置发布状态到主控 + iRet = updatePatchResult(sResult); + if(0 != iRet) + { + NODE_LOG("patchPro")->error() <debug() <debug() <error() <error() <setPatchResult(sResult, iRet == 0); + + //设置发布结果,如果是发布异常了这里也设置,主要是设置进度为100%,方便前端判断 + _serverObjectPtr->setPatched(true); + + //发布后,core频率限制重新计算 + _serverObjectPtr->resetCoreInfo(); + + g_app.reportServer(_patchRequest.appname + "." + _patchRequest.servername, sResult); + + return iRet; +} + +inline int CommandPatch::backupfiles(std::string &sResult) +{ + try + { + if (_serverObjectPtr->getServerType() == "tars_java") //如果是java服务的话需要清空目录,备份目录 + { + int maxbaknum = 5; + string srcPath = "/usr/local/app/tars/tarsnode/data/" + _patchRequest.appname + "." + _patchRequest.servername + "/"; + string destPath = "/usr/local/app/tars/tarsnode/tmp/" + _patchRequest.appname + "." + _patchRequest.servername + "/"; + + if (!TC_File::isFileExistEx(srcPath, S_IFDIR)) //不存在这个目录,先创建 + { + NODE_LOG("patchPro")->debug() <= 1; i--) + { + string destPathBak = + "bin_bak" + TC_Common::tostr(i) + "/"; + if(!TC_File::isFileExistEx(destPathBak,S_IFDIR)) //不存在这个目录,可以继续循环 + { + NODE_LOG("patchPro")->debug() <bak2 + { + string newFile = destPath + "bin_bak" + TC_Common::tostr(i+1) + "/"; + if(TC_File::isFileExistEx(newFile,S_IFDIR) && TC_File::removeFile(newFile, true) != 0) + { + NODE_LOG("patchPro")->error() <debug() <debug() <error() <debug() <debug() <debug() <debug() < vFileNames = TC_Common::sepstr(_serverObjectPtr->getBackupFileNames(), ";|"); + for(vector::size_type i = 0;i< vFileNames.size();i++) + { + string sBackupSrc = destPathBak + vFileNames[i]; + string sBackupDest = existFile + vFileNames[i]; + if (TC_File::isFileExistEx(sBackupSrc,S_IFDIR)) + { + if (!TC_File::isFileExistEx(sBackupDest,S_IFDIR)) + { + if(!TC_File::makeDirRecursive(TC_File::simplifyDirectory(sBackupDest))) + { + NODE_LOG("patchPro")->error() <debug() <error() <error() <getExeFile(); + _logPath = _serverObjectPtr->getLogPath(); + _desc = _serverObjectPtr->getServerDescriptor(); +} +////////////////////////////////////////////////////////////// +// +inline ServerCommand::ExeStatus CommandStart::canExecute(string& sResult) +{ + + TC_ThreadRecLock::Lock lock(*_serverObjectPtr); + + NODE_LOG("startServer")->debug() << FILE_FUN << _desc.application << "." << _desc.serverName << " beging activate------|byRegistry|" << _byNode << endl; + + ServerObject::InternalServerState eState = _serverObjectPtr->getInternalState(); + + if (_byNode) + { + _serverObjectPtr->setEnabled(true); + } + else if (!_serverObjectPtr->isEnabled()) + { + sResult = "server is disabled"; + NODE_LOG("startServer")->debug() << FILE_FUN << sResult << endl; + return DIS_EXECUTABLE; + } + + if (eState == ServerObject::Active || eState == ServerObject::Activating) + { + _serverObjectPtr->synState(); + sResult = "server is already " + _serverObjectPtr->toStringState(eState); + NODE_LOG("startServer")->debug() << FILE_FUN << sResult << endl; + return NO_NEED_EXECUTE; + } + + if (eState != ServerObject::Inactive) + { + sResult = "server state is not Inactive. the curent state is " + _serverObjectPtr->toStringState(eState); + NODE_LOG("startServer")->debug() << FILE_FUN << sResult << endl; + return DIS_EXECUTABLE; + } + + if (TC_File::isAbsolute(_exeFile) && + !TC_File::isFileExistEx(_exeFile) && + _serverObjectPtr->getStartScript().empty() && + _serverObjectPtr->getServerType() != "tars_nodejs" && _serverObjectPtr->getServerType() != "tars_php") + { + _serverObjectPtr->setPatched(false); + sResult = "The server exe patch " + _exeFile + " is not exist."; + NODE_LOG("startServer")->debug() << FILE_FUN << sResult << endl; + return DIS_EXECUTABLE; + } + + _serverObjectPtr->setPatched(true); + + _serverObjectPtr->setState(ServerObject::Activating, false); //此时不通知regisrty。checkpid成功后再通知 + + return EXECUTABLE; +} + +inline bool CommandStart::startByScript(string& sResult) +{ + pid_t iPid = -1; + bool bSucc = false; + string sStartScript = _serverObjectPtr->getStartScript(); + string sMonitorScript = _serverObjectPtr->getMonitorScript(); + + string sServerId = _serverObjectPtr->getServerId(); + iPid = _serverObjectPtr->getActivator()->activate(sServerId, sStartScript, sMonitorScript, sResult); + + vector vtServerName = TC_Common::sepstr(sServerId, "."); + if (vtServerName.size() != 2) + { + sResult = sResult + "|failed to get pid for " + sServerId + ",server id error"; + NODE_LOG("startServer")->error() << FILE_FUN << sResult << endl; + throw runtime_error(sResult); + } + + //默认使用启动脚本路径 + string sFullExeFileName = TC_File::extractFilePath(sStartScript) + vtServerName[1]; + if (!TC_File::isFileExist(sFullExeFileName)) + { + NODE_LOG("startServer")->error() << FILE_FUN << "file name " << sFullExeFileName << " error, use exe file" << endl; + + //使用exe路径 + sFullExeFileName = _serverObjectPtr->getExeFile(); + if (!TC_File::isFileExist(sFullExeFileName)) + { + sResult = sResult + "|failed to get full exe file name|" + sFullExeFileName; + NODE_LOG("startServer")->error() << FILE_FUN << sResult << endl; + throw runtime_error(sResult); + } + } + time_t tNow = TNOW; + int iStartWaitInterval = START_WAIT_INTERVAL; + try + { + //服务启动,超时时间自己定义的情况 + TC_Config conf; + conf.parseFile(_serverObjectPtr->getConfigFile()); + iStartWaitInterval = TC_Common::strto(conf.get("/tars/application/server", "3000")) / 1000; + if (iStartWaitInterval < START_WAIT_INTERVAL) + { + iStartWaitInterval = START_WAIT_INTERVAL; + } + if (iStartWaitInterval > 60) + { + iStartWaitInterval = 60; + } + + } + catch (...) + { + } + + string sPidFile = "/usr/local/app/tars/tarsnode/util/" + sServerId + ".pid"; + string sGetServerPidScript = "ps -ef | grep -v 'grep' |grep -iE ' " + sFullExeFileName + " '| awk '{print $2}' > " + sPidFile; + + while ((TNOW - iStartWaitInterval) < tNow) + { + //注意:由于是守护进程,不要对sytem返回值进行判断,始终wait不到子进程 + system(sGetServerPidScript.c_str()); + string sPid = TC_Common::trim(TC_File::load2str(sPidFile)); + if (TC_Common::isdigit(sPid)) + { + iPid = TC_Common::strto(sPid); + _serverObjectPtr->setPid(iPid); + if (_serverObjectPtr->checkPid() == 0) + { + bSucc = true; + break; + } + } + + NODE_LOG("startServer")->debug() << FILE_FUN << _desc.application << "." << _desc.serverName << " activating usleep " << int(iStartWaitInterval) << endl; + usleep(START_SLEEP_INTERVAL); + } + + if (_serverObjectPtr->checkPid() != 0) + { + sResult = sResult + "|get pid for server[" + sServerId + "],pid is not digit"; + NODE_LOG("startServer")->error() << FILE_FUN << sResult << endl; + if (TC_File::isFileExist(sPidFile)) + { + TC_File::removeFile(sPidFile, false); + } + throw runtime_error(sResult); + } + + if (TC_File::isFileExist(sPidFile)) + { + TC_File::removeFile(sPidFile, false); + } + return bSucc; +} + +inline bool CommandStart::startByScriptPHP(string& sResult) +{ + //生成启动shell脚本 + string sConfigFile = _serverObjectPtr->getConfigFile(); + string sLogPath = _serverObjectPtr->getLogPath(); + string sServerDir = _serverObjectPtr->getServerDir(); + string sLibPath = _serverObjectPtr->getLibPath(); + string sExePath = _serverObjectPtr->getExePath(); + string sLogRealPath = sLogPath + _desc.application +"/" + _desc.serverName + "/" ; + string sLogRealPathFile = sLogRealPath +_serverObjectPtr->getServerId() +".log"; + + TC_Config conf; + conf.parseFile(sConfigFile); + string phpexecPath = ""; + string entrance = ""; + try{ + phpexecPath = TC_Common::strto(conf["/tars/application/server"]); + entrance = TC_Common::strto(conf["/tars/application/server"]); + } catch (...){} + entrance = entrance=="" ? sServerDir+"/bin/src/index.php" : entrance; + + std::ostringstream osStartStcript; + osStartStcript << "#!/bin/sh" << std::endl; + osStartStcript << "if [ ! -d \"" << sLogRealPath << "\" ];then mkdir -p \"" << sLogRealPath << "\"; fi" << std::endl; + osStartStcript << phpexecPath << " " << entrance <<" --config=" << sConfigFile << " start >> " << sLogRealPathFile << " 2>&1 " << std::endl; + osStartStcript << "echo \"end-tars_start.sh\"" << std::endl; + + TC_File::save2file(sExePath + "/tars_start.sh", osStartStcript.str()); + TC_File::setExecutable(sExePath + "/tars_start.sh", true); + + pid_t iPid = -1; + bool bSucc = false; + + string sStartScript = _serverObjectPtr->getStartScript(); + sStartScript = sStartScript=="" ? _serverObjectPtr->getExePath() + "/tars_start.sh" : sStartScript; + string sMonitorScript = _serverObjectPtr->getMonitorScript(); + string sServerId = _serverObjectPtr->getServerId(); + iPid = _serverObjectPtr->getActivator()->activate(sServerId, sStartScript, sMonitorScript, sResult); + + + vector vtServerName = TC_Common::sepstr(sServerId, "."); + if (vtServerName.size() != 2) + { + sResult = sResult + "|failed to get pid for " + sServerId + ",server id error"; + NODE_LOG("startServer")->error() << FILE_FUN << sResult << endl; + throw runtime_error(sResult); + } + + //默认使用启动脚本路径 + string sFullExeFileName = TC_File::extractFilePath(sStartScript) + vtServerName[1]; + time_t tNow = TNOW; + int iStartWaitInterval = START_WAIT_INTERVAL; + try + { + //服务启动,超时时间自己定义的情况 + TC_Config conf; + conf.parseFile(_serverObjectPtr->getConfigFile()); + iStartWaitInterval = TC_Common::strto(conf.get("/tars/application/server", "3000")) / 1000; + if (iStartWaitInterval < START_WAIT_INTERVAL) + { + iStartWaitInterval = START_WAIT_INTERVAL; + } + if (iStartWaitInterval > 60) + { + iStartWaitInterval = 60; + } + + } + catch (...) + { + } + + string sPidFile = "/usr/local/app/tars/tarsnode/util/" + sServerId + ".pid"; + string sGetServerPidScript = "ps -ef | grep -v 'grep' |grep -iE ' " + _desc.application+"."+_desc.serverName + "'|grep master| awk '{print $2}' > " + sPidFile; + + while ((TNOW - iStartWaitInterval) < tNow) + { + //注意:由于是守护进程,不要对sytem返回值进行判断,始终wait不到子进程 + system(sGetServerPidScript.c_str()); + string sPid = TC_Common::trim(TC_File::load2str(sPidFile)); + if (TC_Common::isdigit(sPid)) + { + iPid = TC_Common::strto(sPid); + _serverObjectPtr->setPid(iPid); + if (_serverObjectPtr->checkPid() == 0) + { + bSucc = true; + break; + } + } + + NODE_LOG("startServer")->debug() << FILE_FUN << _desc.application << "." << _desc.serverName << " activating usleep " << int(iStartWaitInterval) << endl; + usleep(START_SLEEP_INTERVAL); + } + + if (_serverObjectPtr->checkPid() != 0) + { + sResult = sResult + "|get pid for server[" + sServerId + "],pid is not digit"; + NODE_LOG("startServer")->error() << FILE_FUN << sResult << endl; + if (TC_File::isFileExist(sPidFile)) + { + TC_File::removeFile(sPidFile, false); + } + throw runtime_error(sResult); + } + + if (TC_File::isFileExist(sPidFile)) + { + TC_File::removeFile(sPidFile, false); + } + return bSucc; +} + +inline bool CommandStart::startNormal(string& sResult) +{ + pid_t iPid = -1; + bool bSucc = false; + string sRollLogFile; + vector vEnvs; + vector vOptions; + string sConfigFile = _serverObjectPtr->getConfigFile(); + string sLogPath = _serverObjectPtr->getLogPath(); + string sServerDir = _serverObjectPtr->getServerDir(); + string sLibPath = _serverObjectPtr->getLibPath(); + string sExePath = _serverObjectPtr->getExePath(); + + //环境变量设置 + vector vecEnvs = TC_Common::sepstr(_serverObjectPtr->getEnv(), ";|"); + for (vector::size_type i = 0; i < vecEnvs.size(); i++) + { + vEnvs.push_back(vecEnvs[i]); + } + + { + vEnvs.push_back("LD_LIBRARY_PATH=$LD_LIBRARY_PATH:" + sExePath + ":" + sLibPath); + } + + //生成启动脚本 + std::ostringstream osStartStcript; + osStartStcript << "#!/bin/sh" << std::endl; + for (vector::size_type i = 0; i < vEnvs.size(); i++) + { + osStartStcript << "export " << vEnvs[i] << std::endl; + } + + osStartStcript << std::endl; + if (_serverObjectPtr->getServerType() == "tars_java") + { + //java服务 + string sClassPath = _serverObjectPtr->getClassPath(); + string sJarList = sExePath + "/classes"; + vector vJarList; + TC_File::scanDir(sClassPath, vJarList); + + sJarList = sJarList + ":" + sClassPath + "/*"; + + vOptions.push_back("-Dconfig=" + sConfigFile); + string s = _serverObjectPtr->getJvmParams() + " -cp " + sJarList + " " + _serverObjectPtr->getMainClass(); + vector v = TC_Common::sepstr(s, " \t"); + vOptions.insert(vOptions.end(), v.begin(), v.end()); + + osStartStcript << _exeFile << " " << TC_Common::tostr(vOptions) << endl; + } + else if (_serverObjectPtr->getServerType() == "tars_nodejs") + { + vOptions.push_back(sExePath + "/tars_nodejs/node-agent/bin/node-agent"); + string s = sExePath + "/src/ -c " + sConfigFile; + vector v = TC_Common::sepstr(s," \t"); + vOptions.insert(vOptions.end(), v.begin(), v.end()); + + //对于tars_nodejs类型需要修改下_exeFile + _exeFile = sExePath+"/tars_nodejs/node"; + + osStartStcript<getServerType() == "tars_php") + { + vOptions.push_back("--config=" + sConfigFile); + osStartStcript << _exeFile << " " << TC_Common::tostr(vOptions) << " &" << endl; + } + else + { + //c++服务 + vOptions.push_back("--config=" + sConfigFile); + osStartStcript << _exeFile << " " << TC_Common::tostr(vOptions) << " &" << endl; + } + + //保存启动方式到bin目录供手工启动 + TC_File::save2file(sExePath + "/tars_start.sh", osStartStcript.str()); + TC_File::setExecutable(sExePath + "/tars_start.sh", true); + + if (sLogPath != "") + { + sRollLogFile = sLogPath + "/" + _desc.application + "/" + _desc.serverName + "/" + _desc.application + "." + _desc.serverName + ".log"; + } + + const string sPwdPath = sLogPath != "" ? sLogPath : sServerDir; //pwd patch 统一设置至log目录 以便core文件发现 删除 + iPid = _serverObjectPtr->getActivator()->activate(_exeFile, sPwdPath, sRollLogFile, vOptions, vEnvs); + if (iPid == 0) //child process + { + return false; + } + + _serverObjectPtr->setPid(iPid); + + bSucc = (_serverObjectPtr->checkPid() == 0) ? true : false; + + return bSucc; +} +////////////////////////////////////////////////////////////// +// +inline int CommandStart::execute(string& sResult) +{ + int64_t startMs = TC_TimeProvider::getInstance()->getNowMs(); + try + { + bool bSucc = false; + //set stdout & stderr + _serverObjectPtr->getActivator()->setRedirectPath(_serverObjectPtr->getRedirectPath()); + + if( TC_Common::lower(TC_Common::trim(_desc.serverType)) == "tars_php" ){ + + bSucc = startByScriptPHP(sResult); + + }else if (!_serverObjectPtr->getStartScript().empty() || _serverObjectPtr->isTarsServer() == false){ + + bSucc = startByScript(sResult); + } + else + { + bSucc = startNormal(sResult); + } + + if (bSucc == true) + { + _serverObjectPtr->synState(); + _serverObjectPtr->setLastKeepAliveTime(TNOW); + _serverObjectPtr->setLimitInfoUpdate(true); + _serverObjectPtr->setStarted(true); + _serverObjectPtr->setStartTime(TNOWMS); + NODE_LOG("startServer")->debug() << FILE_FUN << _desc.application << "." << _desc.serverName << "_" << _desc.nodeName << " start succ " << sResult << ", use:" << (TC_TimeProvider::getInstance()->getNowMs() - startMs) << " ms" << endl; + return 0; + } + } + catch (exception& e) + { + sResult = e.what(); + } + catch (const std::string& e) + { + sResult = e; + } + catch (...) + { + sResult = "catch unkwon exception"; + } + + NODE_LOG("startServer")->error() << FILE_FUN << _desc.application << "." << _desc.serverName << " start failed :" << sResult << ", use:" << (TC_TimeProvider::getInstance()->getNowMs() - startMs) << " ms" << endl; + + _serverObjectPtr->setPid(0); + _serverObjectPtr->setState(ServerObject::Inactive); + _serverObjectPtr->setStarted(false); + + return -1; +} +#endif diff --git a/NodeServer/CommandStop.h b/NodeServer/CommandStop.h new file mode 100644 index 00000000..08993161 --- /dev/null +++ b/NodeServer/CommandStop.h @@ -0,0 +1,269 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __STOP_COMMAND_H_ +#define __STOP_COMMAND_H_ + +#include "ServerCommand.h" + +class CommandStop : public ServerCommand +{ +public: + enum + { + STOP_WAIT_INTERVAL = 2, /*服务关闭等待时间 秒*/ + STOP_SLEEP_INTERVAL = 100000, /*微妙*/ + }; +public: + CommandStop(const ServerObjectPtr& pServerObjectPtr, bool bUseAdmin = true, bool bByNode = false, bool bGenerateCore = false); + + ExeStatus canExecute(string& sResult); + + int execute(string& sResult); + +private: + ServerObjectPtr _serverObjectPtr; + bool _useAdmin; //是否使用管理端口停服务 + bool _byNode; + bool _generateCore; + ServerDescriptor _desc; +}; + +////////////////////////////////////////////////////////////// +// +inline CommandStop::CommandStop(const ServerObjectPtr& pServerObjectPtr, bool bUseAdmin, bool bByNode, bool bGenerateCore) +: _serverObjectPtr(pServerObjectPtr) +, _useAdmin(bUseAdmin) +, _byNode(bByNode) +, _generateCore(bGenerateCore) +{ + _desc = _serverObjectPtr->getServerDescriptor(); +} +////////////////////////////////////////////////////////////// +// +inline ServerCommand::ExeStatus CommandStop::canExecute(string& sResult) +{ + TC_ThreadRecLock::Lock lock(*_serverObjectPtr); + + NODE_LOG("stopServer")->debug() << FILE_FUN << _desc.application << "." << _desc.serverName << " beging deactivate------|byRegistry|" << _byNode << endl; + + ServerObject::InternalServerState eState = _serverObjectPtr->getInternalState(); + + if (_byNode) + { + _serverObjectPtr->setEnabled(false); + } + + if (eState == ServerObject::Inactive) + { + _serverObjectPtr->synState(); + sResult = "server state is Inactive. "; + NODE_LOG("stopServer")->debug() << FILE_FUN << sResult << endl; + return NO_NEED_EXECUTE; + } + + if (eState == ServerObject::Destroying) + { + sResult = "server state is Destroying. "; + NODE_LOG("stopServer")->debug() << FILE_FUN << sResult << endl; + return DIS_EXECUTABLE; + } + + if (eState == ServerObject::Patching || eState == ServerObject::BatchPatching) + { + PatchInfo tPatchInfo; + _serverObjectPtr->getPatchPercent(tPatchInfo); + //状态为Pathing时 10秒无更新才允许stop + std::string sPatchType = eState == ServerObject::BatchPatching ? "BatchPatching" : "Patching"; + time_t iTimes = eState == ServerObject::BatchPatching ? 10 * 60 : 10; + if (TNOW - tPatchInfo.iModifyTime < iTimes) + { + sResult = "server is " + sPatchType + " " + TC_Common::tostr(tPatchInfo.iPercent) + "%, please try again later....."; + NODE_LOG("stopServer")->debug() << FILE_FUN << "CommandStop::canExecute|" << sResult << endl; + return DIS_EXECUTABLE; + } + else + { + NODE_LOG("stopServer")->debug() << FILE_FUN << "server is patching " << tPatchInfo.iPercent << "% ,and no modify info for " << TNOW - tPatchInfo.iModifyTime << "s" << endl; + } + } + + _serverObjectPtr->setState(ServerObject::Deactivating); + + return EXECUTABLE; +} + +////////////////////////////////////////////////////////////// +// +inline int CommandStop::execute(string& sResult) +{ + bool needWait = false; + try + { + pid_t pid = _serverObjectPtr->getPid(); + NODE_LOG("stopServer")->debug() << FILE_FUN << "pid:" << pid << endl; + if (pid != 0) + { + string f = "/proc/" + TC_Common::tostr(pid) + "/status"; + NODE_LOG("stopServer")->debug() << FILE_FUN << "print the server status :" << f << "|" << TC_File::load2str(f) << endl; + } + + string sStopScript = _serverObjectPtr->getStopScript(); + //配置了脚本或者非tars服务 + if( TC_Common::lower(TC_Common::trim(_desc.serverType)) == "tars_php" ){ + //生成停止shell脚本 + string sConfigFile = _serverObjectPtr->getConfigFile(); + string sLogPath = _serverObjectPtr->getLogPath(); + string sServerDir = _serverObjectPtr->getServerDir(); + string sLibPath = _serverObjectPtr->getLibPath(); + string sExePath = _serverObjectPtr->getExePath(); + string sLogRealPath = sLogPath + _desc.application +"/" + _desc.serverName + "/" ; + string sLogRealPathFile = sLogRealPath +_serverObjectPtr->getServerId() +".log"; + + TC_Config conf; + conf.parseFile(sConfigFile); + string phpexecPath = ""; + string entrance = ""; + try{ + phpexecPath = TC_Common::strto(conf["/tars/application/server"]); + entrance = TC_Common::strto(conf["/tars/application/server"]); + } catch (...){} + entrance = entrance=="" ? sServerDir+"/bin/src/index.php" : entrance; + + std::ostringstream osStopStcript; + osStopStcript << "#!/bin/sh" << std::endl; + osStopStcript << "if [ ! -d \"" << sLogRealPath << "\" ];then mkdir -p \"" << sLogRealPath << "\"; fi" << std::endl; + osStopStcript << phpexecPath << " " << entrance <<" --config=" << sConfigFile << " stop >> " << sLogRealPathFile << " 2>&1 " << std::endl; + osStopStcript << "echo \"end-tars_stop.sh\"" << std::endl; + + TC_File::save2file(sExePath + "/tars_stop.sh", osStopStcript.str()); + TC_File::setExecutable(sExePath + "/tars_stop.sh", true); + + sStopScript = sStopScript=="" ? _serverObjectPtr->getExePath() + "/tars_stop.sh" : sStopScript; + + map mResult; + string sServerId = _serverObjectPtr->getServerId(); + _serverObjectPtr->getActivator()->doScript(sServerId, sStopScript, sResult, mResult); + needWait = true; + + }else if (!sStopScript.empty() || _serverObjectPtr->isTarsServer() == false) { + map mResult; + string sServerId = _serverObjectPtr->getServerId(); + _serverObjectPtr->getActivator()->doScript(sServerId, sStopScript, sResult, mResult); + needWait = true; + } + else + { + if (_useAdmin) + { + AdminFPrx pAdminPrx; //服务管理代理 + string sAdminPrx = "AdminObj@" + _serverObjectPtr->getLocalEndpoint().toString(); + NODE_LOG("stopServer")->debug() << FILE_FUN << _desc.application << "." << _desc.serverName + << " call " << sAdminPrx << endl; + pAdminPrx = Application::getCommunicator()->stringToProxy(sAdminPrx); + pAdminPrx->async_shutdown(NULL); + needWait = true; + } + } + + } + catch (exception& e) + { + NODE_LOG("stopServer")->debug() << FILE_FUN << _desc.application << "." << _desc.serverName << " shut down result:|" << e.what() << "|use kill -9 for check" << endl; + pid_t pid = _serverObjectPtr->getPid(); + _serverObjectPtr->getActivator()->deactivate(pid); + } + catch (...) + { + NODE_LOG("stopServer")->debug() << FILE_FUN << _desc.application << "." << _desc.serverName << " shut down fail:|" << "|use kill -9 for check" << endl; + pid_t pid = _serverObjectPtr->getPid(); + _serverObjectPtr->getActivator()->deactivate(pid); + } + + //等待STOP_WAIT_INTERVAL秒 + time_t tNow = TNOW; + int iStopWaitInterval = STOP_WAIT_INTERVAL; + try + { + //服务停止,超时时间自己定义的情况 + TC_Config conf; + conf.parseFile(_serverObjectPtr->getConfigFile()); + iStopWaitInterval = TC_Common::strto(conf["/tars/application/server"]) / 1000; + + if (iStopWaitInterval < STOP_WAIT_INTERVAL) + { + iStopWaitInterval = STOP_WAIT_INTERVAL; + } + + if (iStopWaitInterval > 60) + { + iStopWaitInterval = 60; + } + + } + catch (...) + { + } + + if (needWait) + { + while (TNOW - iStopWaitInterval < tNow) + { + if (_serverObjectPtr->checkPid() != 0) //如果pid已经不存在 + { + _serverObjectPtr->setPid(0); + _serverObjectPtr->setState(ServerObject::Inactive); + _serverObjectPtr->setStarted(false); + NODE_LOG("stopServer")->debug() << FILE_FUN << _desc.application << "." << _desc.serverName << "server already stop" << endl; + return 0; + } + NODE_LOG("stopServer")->debug() << FILE_FUN << _desc.application << "." << _desc.serverName << " deactivating usleep " << int(STOP_SLEEP_INTERVAL) << endl; + usleep(STOP_SLEEP_INTERVAL); + } + NODE_LOG("stopServer")->debug() << FILE_FUN << _desc.application << "." << _desc.serverName << " shut down timeout ( used " << iStopWaitInterval << "'s), use kill -9" << endl; + } + + //仍然失败。用kill -9,再等待STOP_WAIT_INTERVAL秒。 + pid_t pid = _serverObjectPtr->getPid(); + if (_generateCore == true) + { + _serverObjectPtr->getActivator()->deactivateAndGenerateCore(pid); + } + else + { + _serverObjectPtr->getActivator()->deactivate(pid); + } + + tNow = TNOW; + while (TNOW - STOP_WAIT_INTERVAL < tNow) + { + if (_serverObjectPtr->checkPid() != 0) //如果pid已经不存在 + { + _serverObjectPtr->setPid(0); + _serverObjectPtr->setState(ServerObject::Inactive); + _serverObjectPtr->setStarted(false); + return 0; + } + usleep(STOP_SLEEP_INTERVAL); + } + sResult = "server pid " + TC_Common::tostr(pid) + " is still exist"; + + NODE_LOG("stopServer")->debug() << FILE_FUN << _desc.application << "." << _desc.serverName << ", " << sResult << endl; + + return -1; +} + +#endif diff --git a/NodeServer/KeepAliveThread.cpp b/NodeServer/KeepAliveThread.cpp new file mode 100644 index 00000000..af4f14a9 --- /dev/null +++ b/NodeServer/KeepAliveThread.cpp @@ -0,0 +1,352 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "KeepAliveThread.h" +#include "RegistryProxy.h" +#include "NodeRollLogger.h" +#include "util/tc_timeprovider.h" +#include "util.h" + +KeepAliveThread::KeepAliveThread() +: _terminate(false) +, _registryPrx(NULL) +{ + _runTime = time(0); + _nodeInfo = _platformInfo.getNodeInfo(); + _heartTimeout = TC_Common::strto(g_pconf->get("/tars/node/keepalive", "10")); + _monitorInterval = TC_Common::strto(g_pconf->get("/tars/node/keepalive", "2")); + + _monitorIntervalMs = TC_Common::strto(g_pconf->get("/tars/node/keepalive", "10")); + + _synInterval = TC_Common::strto(g_pconf->get("/tars/node/keepalive", "60")); + _synStatBatch = g_pconf->get("/tars/node/keepalive", "Y"); + _monitorInterval = _monitorInterval > 10 ? 10 : (_monitorInterval < 1 ? 1 : _monitorInterval); + +} + +KeepAliveThread::~KeepAliveThread() +{ + terminate(); +} + +void KeepAliveThread::terminate() +{ + NODE_LOG("KeepAliveThread")->debug() << FILE_FUN << endl; + + _terminate = true; + + if (isAlive()) + { + _lock.notifyAll(); + getThreadControl().join(); + } + +} + +bool KeepAliveThread::timedWait(int millsecond) +{ + TC_ThreadLock::Lock lock(_lock); + + if (_terminate) + { + return true; + } + + return _lock.timedWait(millsecond); +} + +void KeepAliveThread::run() +{ + bool bLoaded = false; + bool bRegistered = false; + + while (!_terminate) + { + int64_t startMs = TC_TimeProvider::getInstance()->getNowMs(); + + try + { + //获取主控代理 + if (!_registryPrx) + { + _registryPrx = AdminProxy::getInstance()->getRegistryProxy(); + if (!_registryPrx) + { + NODE_LOG("KeepAliveThread")->debug() << FILE_FUN << "RegistryProxy init fail ! retry it after " + TC_Common::tostr(_monitorInterval) + " second" << endl; + } + } + + //注册node信息 + if (_registryPrx && bRegistered == false) + { + bRegistered = registerNode(); + } + + //加载服务 + if (bLoaded == false) + { + bLoaded = loadAllServers(); + } + + //检查服务的limit配置是否需要更新 + if (bLoaded) + { + ServerFactory::getInstance()->setAllServerResourceLimit(); + } + + //检查服务 + checkAlive(); + + // 上报node状态 + if (reportAlive() != 0) + { + bRegistered = false; //registry服务重启 需要重新注册 + } + } + catch (exception& e) + { + NODE_LOG("KeepAliveThread")->error() << FILE_FUN << "catch exception|" << e.what() << endl; + } + catch (...) + { + NODE_LOG("KeepAliveThread")->error() << FILE_FUN << "catch unkown exception|" << endl; + } + + { + int64_t useMs = (TC_TimeProvider::getInstance()->getNowMs() - startMs); + NODE_LOG("KeepAliveThread")->debug() << FILE_FUN << "run use:" << useMs << " ms" << endl; + } + + timedWait(ServerFactory::getInstance()->getMinMonitorIntervalMs()); + } +} + +bool KeepAliveThread::registerNode() +{ + NODE_LOG("KeepAliveThread")->debug() << FILE_FUN << "registerNode begin===============|node name|" << _nodeInfo.nodeName << endl; + try + { + int iRet = _registryPrx->registerNode(_nodeInfo.nodeName, _nodeInfo, _platformInfo.getLoadInfo()); + + if (iRet == 0) + { + NODE_LOG("KeepAliveThread")->debug() << FILE_FUN << "register node succ" << endl; + return true; + } + } + catch (exception& e) + { + NODE_LOG("KeepAliveThread")->error() << FILE_FUN << "KeepAliveThread::registerNode catch exception|" << e.what() << endl; + } + + NODE_LOG("KeepAliveThread")->debug() << FILE_FUN << "register node fail" << endl; + + return false; +} + +bool KeepAliveThread::loadAllServers() +{ + NODE_LOG("KeepAliveThread")->debug() << FILE_FUN << "load server begin===============|node name|" << _nodeInfo.nodeName << endl; + + /** + * 由于加载失败或者node下没有部署服务,这里就会一直去访问主控 + * 增加这个限制,如果超过5次失败,则不去加载,10分钟重试10次 + * 如果之后有新服务部署,会自动添加到node缓存中,不影响监控流程 + */ + static int iFailNum = 0; + if (iFailNum >= 5) + { + static time_t tLastLoadTime = 0; + if ((TNOW - tLastLoadTime) < 600) + { + NODE_LOG("KeepAliveThread")->error() << FILE_FUN << "load server fail" << endl; + return false; + } + tLastLoadTime = TNOW; + iFailNum = 0; + } + + try + { + if (ServerFactory::getInstance()->loadServer()) + { + NODE_LOG("KeepAliveThread")->debug() << FILE_FUN << "load server succ" << endl; + return true; + } + } + catch (exception& e) + { + NODE_LOG("KeepAliveThread")->error() << FILE_FUN << "catch exception|" << e.what() << endl; + } + + iFailNum++; + + NODE_LOG("KeepAliveThread")->error() << FILE_FUN << "load server fail" << endl; + + return false; +} + +int KeepAliveThread::reportAlive() +{ + try + { + static time_t tReport; + time_t tNow = TNOW; + if (tNow - tReport > _heartTimeout) + { + tReport = tNow; + + NODE_LOG("KeepAliveThread")->debug() << FILE_FUN << "node keep alive ----------------------------------------------------|" << time(0) << "|" << pthread_self() << '\n' << endl; + + int iRet = _registryPrx->keepAlive(_nodeInfo.nodeName, _platformInfo.getLoadInfo()); + + return iRet; + } + } + catch (exception& e) + { + NODE_LOG("KeepAliveThread")->error() << FILE_FUN << "KeepAliveThread::reportAlive catch exception|" << e.what() << endl; + } + + return 0; +} + +int KeepAliveThread::synStat() +{ + try + { + int iRet = -1; + + vector v; + _stat.swap(v); + + NODE_LOG("KeepAliveThread")->debug() << FILE_FUN << "node syn stat size|" << v.size() << "|" << _synStatBatch << "|" << pthread_self() << endl; + + if (v.size() > 0) + { + iRet = _registryPrx->updateServerBatch(v); + } + + return iRet; + } + catch (exception& e) + { + string s = e.what(); + if (s.find("server function mismatch exception") != string::npos) + { + _synStatBatch = "N"; + } + NODE_LOG("KeepAliveThread")->error() << FILE_FUN << "catch exception|" << s << endl; + } + + NODE_LOG("KeepAliveThread")->debug() << FILE_FUN << "fail,set SynStatBatch = " << _synStatBatch << endl; + + return -1; +} + +void KeepAliveThread::checkAlive() +{ + int64_t startMs = TC_TimeProvider::getInstance()->getNowMs(); + + static time_t tSyn = 0; + bool bNeedSynServerState = false; + + time_t tNow = TNOW; + if (tNow - tSyn > _synInterval) + { + tSyn = tNow; + bNeedSynServerState = true; + } + + string sServerId; + + _stat.clear(); + + map mmServerList = ServerFactory::getInstance()->getAllServers(); + map::const_iterator it = mmServerList.begin(); + for (; it != mmServerList.end(); it++) + { + map::const_iterator p = it->second.begin(); + for (; p != it->second.end(); p++) + { + try + { + sServerId = it->first + "." + p->first; + ServerObjectPtr pServerObjectPtr = p->second; + if (!pServerObjectPtr) + { + NODE_LOG("KeepAliveThread")->debug() << FILE_FUN << sServerId << "|=NULL|" << endl; + continue; + } + + pServerObjectPtr->doMonScript(); + + if (TNOW - _runTime < ServantHandle::HEART_BEAT_INTERVAL * 5) + { + //等待心跳包 + continue; + } + + //corelimit checking + pServerObjectPtr->checkCoredumpLimit(); + + //(checkServer时,上报Server所占用的内存给主控) + pServerObjectPtr->checkServer(_heartTimeout); + + //cache 同步server 状态 + if (bNeedSynServerState == true) + { + ServerInfo tServerInfo; + tServerInfo.application = it->first; + tServerInfo.serverName = p->first; + ServerDescriptor tServerDescriptor = pServerObjectPtr->getServerDescriptor(); + tServerDescriptor.settingState = pServerObjectPtr->isEnabled() == true ? "active" : "inactive"; + g_serverInfoHashmap.set(tServerInfo, tServerDescriptor); + + ServerStateInfo tServerStateInfo; + tServerStateInfo.serverState = (pServerObjectPtr->IsEnSynState() ? pServerObjectPtr->getState() : tars::Inactive); + tServerStateInfo.processId = pServerObjectPtr->getPid(); + tServerStateInfo.nodeName = _nodeInfo.nodeName; + tServerStateInfo.application = it->first; + tServerStateInfo.serverName = p->first; + + if (TC_Common::lower(_synStatBatch) == "y") + { + _stat.push_back(tServerStateInfo); + } + else + { + pServerObjectPtr->asyncSynState(); + } + } + } + catch (exception& e) + { + NODE_LOG("KeepAliveThread")->error() << FILE_FUN << sServerId << " catch exception|" << e.what() << endl; + } + } + } + + if (bNeedSynServerState) + { + synStat(); + } + + { + int64_t useMs = (TC_TimeProvider::getInstance()->getNowMs() - startMs); + NODE_LOG("KeepAliveThread")->debug() << FILE_FUN << "checkAlive use:" << useMs << " ms" << endl; + } +} diff --git a/NodeServer/KeepAliveThread.h b/NodeServer/KeepAliveThread.h new file mode 100644 index 00000000..fe5c991a --- /dev/null +++ b/NodeServer/KeepAliveThread.h @@ -0,0 +1,105 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __KEEP_ALIVE_THREAD_H_ +#define __KEEP_ALIVE_THREAD_H_ +#include "Node.h" +#include +#include "ServerFactory.h" +#include "util/tc_monitor.h" +#include "util/tc_thread.h" +#include "PlatformInfo.h" + +using namespace tars; +using namespace std; + +class KeepAliveThread : public TC_Thread//,public TC_ThreadLock +{ +public: + /** + * 构造函数 + */ + KeepAliveThread(); + + /** + * 析构函数 + */ + ~KeepAliveThread(); + + /** + * 结束线程 + */ + void terminate(); + +protected: + + virtual void run(); + + /** + * 往registry注册node信息 + */ + bool registerNode(); + + /** + * 获取本node在registry配置服务信息 + */ + bool loadAllServers(); + + /** + * 上报registry node当前状态 + * @return int 非0失败 + */ + int reportAlive(); + + /** + * 检查node上server状态 + */ + void checkAlive(); + + /** + * 与registry 同步node上所属服务状态 + */ + int synStat(); + + /** + * 等待 + */ + bool timedWait(int millsecond); + +protected: + + NodeInfo _nodeInfo; + PlatformInfo _platformInfo; + + bool _terminate; + time_t _runTime; //node运行时间 + int _heartTimeout; //业务心跳超时时间(s) + int _monitorInterval; //监控server状态的间隔时间(s) + int _monitorIntervalMs; //新的监控状态间隔,改成毫秒 + int _synInterval; //同步与regisrty server状态的间隔时间(s) + string _synStatBatch; //批量同步 + + RegistryPrx _registryPrx; + +private: + + vector _stat; //服务状态列表 + TC_ThreadLock _lock; +}; + + +#endif + diff --git a/NodeServer/NodeImp.cpp b/NodeServer/NodeImp.cpp new file mode 100644 index 00000000..97d14b6b --- /dev/null +++ b/NodeServer/NodeImp.cpp @@ -0,0 +1,771 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "util/tc_clientsocket.h" +#include "BatchPatchThread.h" +#include "NodeImp.h" +#include "RegistryProxy.h" +#include "NodeServer.h" +#include "CommandStart.h" +#include "CommandNotify.h" +#include "CommandStop.h" +#include "CommandDestroy.h" +#include "CommandAddFile.h" +#include "CommandPatch.h" +#include "NodeRollLogger.h" +#include "AdminReg.h" +#include "util/tc_timeprovider.h" + +extern BatchPatch * g_BatchPatchThread; + +void NodeImp::initialize() +{ + try + { + TLOGDEBUG("initialize NodeImp" << endl); + + _nodeInfo = _platformInfo.getNodeInfo(); + _downloadPath = _platformInfo.getDownLoadDir(); + } + catch ( exception& e ) + { + TLOGERROR(FILE_FUN << e.what() << endl); + exit( 0 ); + } +} + +int NodeImp::destroyServer( const string& application, const string& serverName,string &result, TarsCurrentPtr current ) +{ + int64_t startMs = TC_TimeProvider::getInstance()->getNowMs(); + + int iRet = EM_TARS_SUCCESS; + if ( g_app.isValid(current->getIp()) == false ) + { + result += " erro:ip "+ current->getIp()+" is invalid"; + iRet = EM_TARS_INVALID_IP_ERR; + NODE_LOG("destroyServer")->error() << FILE_FUN << "access_log|" << iRet << "|" << (TC_TimeProvider::getInstance()->getNowMs() - startMs) + << "|" << application << "." << serverName << "|" << result << endl; + return iRet; + } + + result = " ["+application + "." + serverName+"] "; + NODE_LOG("destroyServer")->debug() << result << endl; + ServerObjectPtr pServerObjectPtr = ServerFactory::getInstance()->getServer( application, serverName ); + if ( pServerObjectPtr ) + { + string s; + CommandDestroy command(pServerObjectPtr); + iRet = command.doProcess(current, s, false); + if ( iRet == 0 && ServerFactory::getInstance()->eraseServer(application, serverName) == 0) + { + pServerObjectPtr = NULL; + result = result+"succ:" + s; + } + else + { + result = FILE_FUN_STR+"error:"+s; + } + } + else + { + result += FILE_FUN_STR+"server is not exist"; + iRet = -2; + } + + NODE_LOG("destroyServer")->error() << FILE_FUN << "access_log|" << iRet << "|" << (TC_TimeProvider::getInstance()->getNowMs() - startMs) + << "|" << application << "|" << serverName << "|" << result << endl; + return iRet; +} + +int NodeImp::patchPro(const tars::PatchRequest & req, string & result, TarsCurrentPtr current) +{ + NODE_LOG("patchPro")->debug() << FILE_FUN + << req.appname + "." + req.servername + "_" + req.nodename << "|" + << req.groupname << "|" + << req.version << "|" + << req.user << "|" + << req.servertype << "|" + << req.patchobj << "|" + << req.md5 << "|" + << req.ostype << endl; + + if ( g_app.isValid(current->getIp()) == false ) + { + result +=FILE_FUN_STR+ " erro:ip "+ current->getIp()+" is invalid"; + NODE_LOG("patchPro")->error()<loadServer(req.appname, req.servername, true, sError); + if (!server) + { + result =FILE_FUN_STR+ "load " + req.appname + "." + req.servername + "|" + sError; + NODE_LOG("patchPro")->error() <getInternalState(); + + //去掉启动中不能发布的限制 + if (server->toStringState(eState).find("ing") != string::npos && eState != ServerObject::Activating) + { + result = FILE_FUN_STR+"cannot patch the server ,the server state is " + server->toStringState(eState); + NODE_LOG("patchPro")->error() <error() <error() <debug() <toStringState(eState) << endl; + server->setLastState(eState); + server->setState(ServerObject::BatchPatching); + //将百分比初始化为0,防止上次patch结果影响本次patch进度 + server->setPatchPercent(0); + + NODE_LOG("patchPro")->debug()<push_back(req,server); + } + catch (std::exception & ex) + { + NODE_LOG("patchPro")->error() <error() <debug() <getServer( application, serverName ); + if ( pServerObjectPtr ) + { + string s; + CommandAddFile command(pServerObjectPtr,file); + int iRet = command.doProcess(current,s); + if ( iRet == 0) + { + result = result+"succ:" + s; + } + else + { + result = FILE_FUN_STR+"error:"+s; + } + return iRet; + } + + result += FILE_FUN_STR+"server is not exist"; + + return -1; +} + +string NodeImp::getName( TarsCurrentPtr current ) +{ + TLOGDEBUG(FILE_FUN << endl); + + _nodeInfo = _platformInfo.getNodeInfo(); + + return _nodeInfo.nodeName; +} + +LoadInfo NodeImp::getLoad( TarsCurrentPtr current ) +{ + TLOGDEBUG(FILE_FUN<< endl); + + return _platformInfo.getLoadInfo(); +} + +int NodeImp::shutdown( string &result,TarsCurrentPtr current ) +{ + try + { + result = FILE_FUN_STR; + + TLOGDEBUG( result << endl); + if ( g_app.isValid(current->getIp()) == false ) + { + result += "erro:ip "+ current->getIp()+" is invalid"; + TLOGERROR(FILE_FUN << result << endl); + return -1; + } + Application::terminate(); + return 0; + } + catch ( exception& e ) + { + TLOGERROR( "NodeImp::shutdown catch exception :" << e.what() << endl); + } + catch ( ... ) + { + TLOGERROR( "NodeImp::shutdown catch unkown exception" << endl); + } + return -1; +} + +int NodeImp::stopAllServers( string &result,TarsCurrentPtr current ) +{ + try + { + if ( g_app.isValid(current->getIp()) == false ) + { + result = FILE_FUN_STR+" erro:ip "+ current->getIp()+" is invalid"; + TLOGERROR( result << endl); + return -1; + } + map mmServerList; + mmServerList.clear(); + mmServerList = ServerFactory::getInstance()->getAllServers(); + for ( map::const_iterator it = mmServerList.begin(); it != mmServerList.end(); it++ ) + { + for ( map::const_iterator p = it->second.begin(); p != it->second.end(); p++ ) + { + ServerObjectPtr pServerObjectPtr = p->second; + if ( pServerObjectPtr ) + { + result =result+"stop server ["+it->first+"."+ p->first+"] "; + TLOGDEBUG(FILE_FUN << result << endl); + + bool bByNode = true; + string s; + CommandStop command(pServerObjectPtr,true,bByNode); + int iRet = command.doProcess(s); + if (iRet == 0) + { + result = result+"succ:"+s+"\n"; + } + else + { + result = result+"error:"+s+"\n"; + } + } + } + } + return 0; + } + catch ( exception& e ) + { + TLOGERROR( FILE_FUN<<" catch exception :" << e.what() << endl); + result += e.what(); + } + catch ( ... ) + { + TLOGERROR( FILE_FUN<<" catch unkown exception" << endl); + result += "catch unkown exception"; + } + TLOGDEBUG("stop succ"<getIp()) == false ) + { + result += " erro:ip "+ current->getIp()+" is invalid"; + TLOGERROR(FILE_FUN << result << endl); + return -1; + } + + string s; + + ServerObjectPtr pServerObjectPtr = ServerFactory::getInstance()->loadServer(application,serverName,false,s); + if (!pServerObjectPtr) + { + result =result+" error::cannot load server description.\n"+s; + return EM_TARS_LOAD_SERVICE_DESC_ERR; + } + result = result + " succ" + s; + return 0; + } + catch ( exception& e ) + { + TLOGERROR( FILE_FUN<<" catch exception :" << e.what() << endl); + result += e.what(); + } + catch ( ... ) + { + TLOGERROR( FILE_FUN<<" catch unkown exception" << endl); + result += "catch unkown exception"; + } + return -1; +} + +int NodeImp::startServer( const string& application, const string& serverName,string &result, TarsCurrentPtr current ) +{ + int iRet = EM_TARS_UNKNOWN_ERR; + try + { + result = string(__FUNCTION__)+ " ["+application + "." + serverName+"] from "+ current->getIp()+" "; + NODE_LOG("startServer")->debug()<getIp()) == false ) + { + result += " erro:ip "+ current->getIp()+" is invalid"; + NODE_LOG("startServer")->error()<debug()<loadServer( application, serverName,true,s); + NODE_LOG("startServer")->debug()<debug()<getServer( application, serverName ); + if (pServerObjectPtr) + { + pServerObjectPtr->setEnabled(true); + } + + result += "error::cannot load server description from regisrty.\n" + s; + iRet = EM_TARS_LOAD_SERVICE_DESC_ERR; + } + catch ( exception& e ) + { + NODE_LOG("startServer")->error() << FILE_FUN << " catch exception:" << e.what() << endl; + result += e.what(); + } + catch ( ... ) + { + NODE_LOG("startServer")->error() << FILE_FUN <<" catch unkown exception" << endl; + result += "catch unkown exception"; + } + return iRet; +} + +int NodeImp::stopServer( const string& application, const string& serverName,string &result, TarsCurrentPtr current ) +{ + int iRet = EM_TARS_UNKNOWN_ERR; + try + { + result = string(__FUNCTION__)+" ["+application + "." + serverName+"] from "+ current->getIp()+" "; + + NODE_LOG("stopServer")->debug() <getServer( application, serverName ); + if ( pServerObjectPtr ) + { + string s; + bool bByNode = true; + CommandStop command(pServerObjectPtr,true, bByNode); + iRet = command.doProcess(current,s); + if (iRet == 0 ) + { + result = result+"succ:"+s; + } + else + { + result = result+"error:"+s; + } + NODE_LOG("stopServer")->debug()<error() << FILE_FUN<<" catch exception :" << e.what() << endl; + result += e.what(); + } + catch ( ... ) + { + NODE_LOG("stopServer")->error() << FILE_FUN<<" catch unkown exception" << endl; + result += "catch unkown exception"; + } + return EM_TARS_UNKNOWN_ERR; +} + +int NodeImp::notifyServer( const string& application, const string& serverName, const string &sMsg, string &result, TarsCurrentPtr current ) +{ + try + { + result = string(__FUNCTION__)+" ["+application + "." + serverName+"] '" + sMsg + "' "; + TLOGDEBUG(result<getIp()) == false ) + { + result += " erro:ip "+ current->getIp()+" is invalid"; + TLOGERROR("NodeImp::notifyServer " << result << endl); + return EM_TARS_INVALID_IP_ERR; + } + + if ( application == "tars" && serverName == "tarsnode" ) + { + AdminFPrx pAdminPrx; //服务管理代理 + pAdminPrx = Application::getCommunicator()->stringToProxy("AdminObj@"+ServerConfig::Local); + result = pAdminPrx->notify(sMsg); + return 0; + } + + ServerObjectPtr pServerObjectPtr = ServerFactory::getInstance()->getServer( application, serverName ); + if ( pServerObjectPtr ) + { + string s; + CommandNotify command(pServerObjectPtr,sMsg); + int iRet = command.doProcess(s); + if (iRet == 0 ) + { + result = result + "succ:" + s; + } + else + { + result = result + "error:" + s; + } + return iRet; + } + + result += "server is not exist"; + } + catch ( exception& e ) + { + TLOGERROR( "NodeImp::notifyServer catch exception :" << e.what() << endl); + result += e.what(); + } + catch ( ... ) + { + TLOGERROR( "NodeImp::notifyServer catch unkown exception" << endl); + result += "catch unkown exception"; + } + return -1; +} + +int NodeImp::getServerPid( const string& application, const string& serverName,string &result,TarsCurrentPtr current ) +{ + result = string(__FUNCTION__)+" ["+application + "." + serverName+"] "; + TLOGDEBUG("NodeImp::getServerPid " <getServer( application, serverName ); + if ( pServerObjectPtr ) + { + result += "succ"; + return pServerObjectPtr->getPid(); + } + result += "server not exist"; + return -1; +} + +ServerState NodeImp::getSettingState( const string& application, const string& serverName,string &result, TarsCurrentPtr current ) +{ + result = string(__FUNCTION__)+" ["+application + "." + serverName+"] "; + ServerObjectPtr pServerObjectPtr = ServerFactory::getInstance()->getServer( application, serverName ); + if ( pServerObjectPtr ) + { + result += "succ"; + return pServerObjectPtr->isEnabled()==true?tars::Active:tars::Inactive; + } + result += "server not exist"; + TLOGERROR( "NodeImp::getServerPid" <<" "<getServer( application, serverName ); + if ( pServerObjectPtr ) + { + result += "succ"; + return pServerObjectPtr->getState(); + } + result += "server not exist"; + TLOGERROR("NodeImp::getState " << result << endl); + return tars::Inactive; +} + +tars::Int32 NodeImp::getStateInfo(const std::string & application,const std::string & serverName,tars::ServerStateInfo &info,std::string &result,tars::TarsCurrentPtr current) +{ + result = string(__FUNCTION__)+" ["+application + "." + serverName+"] "; + ServerObjectPtr pServerObjectPtr = ServerFactory::getInstance()->getServer( application, serverName ); + if ( pServerObjectPtr ) + { + result += "succ"; + + info.serverState = pServerObjectPtr->getState(); + info.processId = pServerObjectPtr->getPid(); + info.settingState = pServerObjectPtr->isEnabled()==true?tars::Active:tars::Inactive; + + TLOGDEBUG("NodeImp::getStateInfo " <getServer( application, serverName ); + if ( pServerObjectPtr ) + { + result += "succ"; + pServerObjectPtr->synState(); + return 0; + } + result += "server not exist"; + TLOGERROR("NodeImp::synState "<getServer( application, serverName ); + if ( pServerObjectPtr ) + { + result += "succ"; + NODE_LOG("getPatchPercent")->debug()<getPatchPercent(tPatchInfo); + } + + result += "server not exist"; + NODE_LOG("getPatchPercent")->error() << FILE_FUN <<" "<< result<< endl; + return EM_TARS_LOAD_SERVICE_DESC_ERR; + } + catch ( exception& e ) + { + NODE_LOG("getPatchPercent")->error() << FILE_FUN << " catch exception :" << e.what() << endl; + result += e.what(); + } + catch ( ... ) + { + NODE_LOG("getPatchPercent")->error() << FILE_FUN <<" catch unkown exception" << endl; + result += "catch unkown exception"; + } + + return EM_TARS_UNKNOWN_ERR; + +} + +tars::Int32 NodeImp::delCache(const string &sFullCacheName, const std::string &sBackupPath, const std::string & sKey, std :: string &result, TarsCurrentPtr current) +{ + try + { + TLOGDEBUG("NodeImp::delCache "<(sKey); + } + TLOGDEBUG("NodeImp::delCache|key=" << key << endl); + + int shmid = shmget(key, 0, 0666); + if (shmid == -1) + { + result = "failed to shmget " + sBasePath + "|key=" + TC_Common::tostr(key); + //如果获取失败则认为共享内存已经删除,直接返回成功 + TLOGDEBUG("NodeImp::delCache"<< "|" << sFullCacheName << "|" << result << endl); + return 0; + } + + shmid_ds *pShmInfo= new shmid_ds; + int iRet = shmctl(shmid, IPC_STAT, pShmInfo); + if (iRet != 0) + { + result = "failed to shmctl " + sBasePath + "|key=" + TC_Common::tostr(key) + "|ret=" + TC_Common::tostr(iRet); + delete pShmInfo; + pShmInfo = NULL; + throw runtime_error(result); + } + + if (pShmInfo->shm_nattch>=1) + { + result = "current attach count >= 1,please check it |" + sBasePath + "|key=" +TC_Common::tostr(key)+"|attch_count=" + TC_Common::tostr(pShmInfo->shm_nattch); + delete pShmInfo; + pShmInfo = NULL; + throw runtime_error(result); + }; + + delete pShmInfo; + pShmInfo = NULL; + + int ret =shmctl(shmid, IPC_RMID, NULL); + if (ret !=0) + { + result = "failed to rm share memory|key=" + TC_Common::tostr(key) + "|shmid=" + TC_Common::tostr(shmid) + "|ret=" + TC_Common::tostr(ret); + throw runtime_error(result); + } + + TLOGDEBUG("NodeImp::delCache success delete cache:" << sFullCacheName <<", no need backup it"<< endl); + + return 0; + } + catch ( exception& e ) + { + result = TC_Common::tostr(__FILE__)+":"+TC_Common::tostr(__FUNCTION__) + ":"+ TC_Common::tostr(__LINE__) + "|" + e.what(); + TLOGERROR("NodeImp::delCache " << result << endl); + TARS_NOTIFY_ERROR(result); + } + + return -1; +} + +tars::Int32 NodeImp::getUnusedShmKeys(tars::Int32 count,vector &shm_keys,tars::TarsCurrentPtr current) { + int ret = 0; + for(size_t i = 0; i < 256 && shm_keys.size() < (size_t)count; i++) + { + key_t key = ftok(ServerConfig::BasePath.c_str(), i); + if(key == -1) + { + TLOGDEBUG("NodeImp::getUnusedShmKeys create an key failed, i=" << i << endl); + } + else + { + int shmid = shmget(key, 0, 0666); + if(shmid == -1) + { + TLOGDEBUG("NodeImp::getUnusedShmKeys find an key:" << key << " 0x" << keyToStr(key) << endl); + shm_keys.push_back(key); + } + else + { + TLOGDEBUG("NodeImp::getUnusedShmKeys key: " << key << " 0x" << keyToStr(key) << " is busy"<< endl); + } + } + } + + return ret; +} + +string NodeImp::keyToStr(key_t key_value) +{ + char buf[32]; + snprintf(buf, 32, "%08x", key_value); + string s(buf); + return s; +} +/*********************************************************************/ + + + + + diff --git a/NodeServer/NodeImp.h b/NodeServer/NodeImp.h new file mode 100644 index 00000000..0ef6a932 --- /dev/null +++ b/NodeServer/NodeImp.h @@ -0,0 +1,208 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __NODE_IMP_H_ +#define __NODE_IMP_H_ +#include "Node.h" +#include +#include "PlatformInfo.h" +#include "Activator.h" +#include "KeepAliveThread.h" +#include "tars_patch.h" + +using namespace tars; +using namespace std; + +class NodeImp : public Node +{ +public: + /** + * 构造函数 + */ + NodeImp() + { + } + + /** + * 析构函数 + */ + ~NodeImp() + { + } + + /** + * 初始化 + */ + virtual void initialize(); + + /** + * 退出 + */ + virtual void destroy() + { + } + + /** + * 销毁指定服务 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @return int + */ + virtual int destroyServer( const string& application, const string& serverName, string &result,TarsCurrentPtr current ); + + /** + * 增强的发布接口 + * pushRequest 插入发布请求到队列 + * @param req 发布请求 + * @return int 0成功 其它失败 + */ + int patchPro(const tars::PatchRequest & req, string & result, TarsCurrentPtr current); + + /** + * 加载指定文件 + * @param out result 失败说明 + * @return int 0成功 非0失败 + */ + virtual int addFile(const string &application,const string &serverName,const string &file, string &result, TarsCurrentPtr current); + + /** + * 获取node名称 + * @return string + */ + virtual string getName( TarsCurrentPtr current ) ; + + /** + * 获取node上负载 + * @return LoadInfo + */ + virtual tars::LoadInfo getLoad( TarsCurrentPtr current ) ; + + /** + * 关闭node + * @return int + */ + virtual int shutdown( string &result, TarsCurrentPtr current ); + + /** + * 关闭nodes上所有服务 + * @return int + */ + virtual int stopAllServers( string &result,TarsCurrentPtr current ); + + /** + * 载入指定服务 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @return int + */ + virtual int loadServer( const string& application, const string& serverName, string &result, TarsCurrentPtr current ); + + /** + * 启动指定服务 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @return int + */ + virtual int startServer( const string& application, const string& serverName, string &result, TarsCurrentPtr current ) ; + + /** + * 停止指定服务 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @return int + */ + virtual int stopServer( const string& application, const string& serverName, string &result, TarsCurrentPtr current ) ; + + /** + * 通知服务 + * @param application + * @param serverName + * @param result + * @param current + * + * @return int + */ + virtual int notifyServer( const string& application, const string& serverName, const string &command, string &result, TarsCurrentPtr current ); + + /** + * 获取指定服务pid进程号 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @return int + */ + int getServerPid( const string& application, const string& serverName, string &result, TarsCurrentPtr current); + + /** + * 获取指定服务registry设置的状态 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @return int + */ + virtual ServerState getSettingState( const string& application, const string& serverName, string &result, TarsCurrentPtr current ) ; + + /** + * 获取指定服务状态 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @return ServerState + */ + virtual ServerState getState( const string& application, const string& serverName, string &result, TarsCurrentPtr current ) ; + + /** + * 获取指定服务在node的信息 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @return ServerState + */ + virtual int getStateInfo(const std::string & application,const std::string & serverName,tars::ServerStateInfo &info,std::string &result,tars::TarsCurrentPtr current); + + /** + * 同步指定服务状态 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @return int + */ + virtual int synState( const string& application, const string& serverName, string &result, TarsCurrentPtr current ) ; + + /** + * 发布服务进度 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @out tPatchInfo 下载信息 + * @return int + */ + virtual int getPatchPercent( const string& application, const string& serverName, PatchInfo &tPatchInfo, TarsCurrentPtr current); + + virtual tars::Int32 delCache(const std::string & sFullCacheName, const std::string &sBackupPath, const std::string & sKey, std::string &result,TarsCurrentPtr current); + + virtual tars::Int32 getUnusedShmKeys(tars::Int32 count,vector &shm_keys,tars::TarsCurrentPtr current); + +private: + string keyToStr(key_t key_value); + +private: + + string _downloadPath; //文件下载目录 + NodeInfo _nodeInfo; //node信息 + PlatformInfo _platformInfo; //平台信息 + RegistryPrx _registryPrx; //主控代理 + +}; + +typedef TC_AutoPtr NodeImpPtr; + +#endif + diff --git a/NodeServer/NodeRollLogger.cpp b/NodeServer/NodeRollLogger.cpp new file mode 100644 index 00000000..2fc296cd --- /dev/null +++ b/NodeServer/NodeRollLogger.cpp @@ -0,0 +1,107 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "NodeRollLogger.h" +#include "servant/Communicator.h" + + +///////////////////////////////////////////////////////////////////////////////////// +RollLoggerManager::RollLoggerManager() +: _maxSize(1024 * 1024 * 50), _maxNum(10) +{ +} + +RollLoggerManager::~RollLoggerManager() +{ + + map::iterator it = _loggers.begin(); + while(it != _loggers.end()) + { + delete it->second; + ++it; + } + _loggers.clear(); +} + +void RollLoggerManager::setLogInfo(const string &sApp, const string &sServer, const string &sLogpath, int iMaxSize, int iMaxNum, const CommunicatorPtr &comm, const string &sLogObj) +//void RollLoggerManager::setLogInfo(const string &sApp, const string &sServer, const string &sLogpath, int iMaxSize, int iMaxNum, const string &sLogObj) +{ + _app = sApp; + _server = sServer; + _logpath = sLogpath; + + _maxSize = iMaxSize; + _maxNum = iMaxNum; + _comm = comm; + _logObj = sLogObj; + //生成目录 + TC_File::makeDirRecursive(_logpath + "/" + _app + "/" + _server); + + _local.start(1); +} + + +void RollLoggerManager::sync(RollLogger *pRollLogger, bool bSync) +{ + if(bSync) + { + pRollLogger->unSetupThread(); + } + else + { + pRollLogger->setupThread(&_local); + } +} + +/* +void NodeRollLogger::enableDyeing(bool bEnable, const string& sDyeingKey) +{ + _logger.getRoll()->enableDyeing(bEnable, sDyeingKey); +} +*/ + +RollLoggerManager::RollLogger* RollLoggerManager::logger(const string &sFile) +{ + Lock lock(*this); + map::iterator it = _loggers.find(sFile); + if( it == _loggers.end()) + { + RollLogger *p = new RollLogger(); + //p->modFlag(RollLogger::HAS_MTIME); + initRollLogger(p, sFile, "%Y%m%d"); + _loggers[sFile] = p; + return p; + } + + return it->second; +} + +void RollLoggerManager::initRollLogger(RollLogger *pRollLogger, const string &sFile, const string &sFormat) +{ + + //初始化本地循环日志 + pRollLogger->init(_logpath + "/" + _app + "/" + _server + "/" + _app + "." + _server + "_" + sFile, _maxSize, _maxNum); + pRollLogger->modFlag(TC_DayLogger::HAS_TIME, false); + pRollLogger->modFlag(TC_DayLogger::HAS_TIME|TC_DayLogger::HAS_LEVEL|TC_DayLogger::HAS_PID, true); + + //设置为异步 + sync(pRollLogger, false); + + + //设置染色日志信息 + pRollLogger->getWriteT().setDyeingLogInfo(_app, _server, _logpath, _maxSize, _maxNum, _comm, _logObj); +// pRollLogger->getWriteT().setDyeingLogInfo(_app, _server, _logpath, _maxSize, _maxNum, _logObj); +} diff --git a/NodeServer/NodeRollLogger.h b/NodeServer/NodeRollLogger.h new file mode 100644 index 00000000..9beddff1 --- /dev/null +++ b/NodeServer/NodeRollLogger.h @@ -0,0 +1,120 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __NODE_ROLL_LOGGER_H__ +#define __NODE_ROLL_LOGGER_H__ + +#include "util/tc_logger.h" +#include "servant/TarsLogger.h" + +/** + * node使用的日志,主要是为了支持多个滚动日志 + */ + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 本地日志帮助类, 单件 + * 循环日志单件是永生不死的, 保证任何地方都可以使用 + * 当该对象析够以后, 则直接cout出来 + */ +class RollLoggerManager : public TC_ThreadLock, public TC_Singleton +{ +public: + enum + { + NONE_LOG = 1, /**所有的log都不写*/ + ERROR_LOG = 2, /**写错误log*/ + WARN_LOG = 3, /**写错误,警告log*/ + DEBUG_LOG = 4, /**写错误,警告,调试log*/ + INFO_LOG = 5 /**写错误,警告,调试,Info log*/ + }; +public: + + typedef TC_Logger RollLogger; + + RollLoggerManager(); + + ~RollLoggerManager(); + + /** + * 设置本地信息 + * @param app, 业务名称 + * @param server, 服务名称 + * @param logpath, 日志路径 + * @param iMaxSize, 文件最大大小,字节 + * @param iMaxNum, 文件最大数 + */ + void setLogInfo(const string &sApp, const string &sServer, const string &sLogpath, int iMaxSize = 1024*1024*50, int iMaxNum = 10, const CommunicatorPtr &comm=NULL, const string &sLogObj=""); + + /** + * 设置同步写日志 + * + * @param bSync + */ + void sync(RollLogger *pRollLogger, bool bSync = true); + + /** + * 获取循环日志 + * + * @return RollLogger + */ + RollLogger *logger(const string &sFile); + +private: + void initRollLogger(RollLogger *pRollLogger, const string &sFile, const string &sFormat); + +protected: + + /** + * 应用 + */ + string _app; + + /** + * 服务名称 + */ + string _server; + + /** + * 日志路径 + */ + string _logpath; + + int _maxSize; + int _maxNum; + CommunicatorPtr _comm; + string _logObj; + + /** + * 本地线程组 + */ + TC_LoggerThreadGroup _local; + + /** + * 远程日志 + */ + map _loggers; + +}; + + +/** + * 循环日志 + */ +#define NODE_LOG(x) (RollLoggerManager::getInstance()->logger(x)) +#endif + diff --git a/NodeServer/NodeServer.cpp b/NodeServer/NodeServer.cpp new file mode 100644 index 00000000..b4fa039e --- /dev/null +++ b/NodeServer/NodeServer.cpp @@ -0,0 +1,366 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "NodeServer.h" +#include "NodeImp.h" +#include "ServerImp.h" +#include "RegistryProxy.h" +#include "NodeRollLogger.h" + +string NodeServer::g_sNodeIp; + +BatchPatch *g_BatchPatchThread; +RemoveLogManager *g_RemoveLogThread; + +void NodeServer::initialize() +{ + //滚动日志也打印毫秒 + TarsRollLogger::getInstance()->logger()->modFlag(TC_DayLogger::HAS_MTIME); + + //node使用的循环日志初始化 + RollLoggerManager::getInstance()->setLogInfo(ServerConfig::Application, + ServerConfig::ServerName, ServerConfig::LogPath, + ServerConfig::LogSize, ServerConfig::LogNum, _communicator, + ServerConfig::Log); + + initRegistryObj(); + + addConfig("tarsnode.conf"); + + //增加对象 + string sNodeObj = ServerConfig::Application + "." + ServerConfig::ServerName + ".NodeObj"; + string sServerObj = ServerConfig::Application + "." + ServerConfig::ServerName + ".ServerObj"; + + addServant(sNodeObj); + addServant(sServerObj); + + TLOGDEBUG("NodeServer::initialize ServerAdapter " << (getAdapterEndpoint("ServerAdapter")).toString() << endl); + TLOGDEBUG("NodeServer::initialize NodeAdapter " << (getAdapterEndpoint("NodeAdapter")).toString() << endl); + + g_sNodeIp = getAdapterEndpoint("NodeAdapter").getHost(); + + if (!ServerFactory::getInstance()->loadConfig()) + { + TLOGERROR("NodeServer::initialize ServerFactory loadConfig failure" << endl); + } + + //查看服务desc + TARS_ADD_ADMIN_CMD_PREFIX("tars.serverdesc", NodeServer::cmdViewServerDesc); + TARS_ADD_ADMIN_CMD_PREFIX("reloadconfig", NodeServer::cmdReLoadConfig); + + initHashMap(); + + //启动KeepAliveThread + _keepAliveThread = new KeepAliveThread(); + _keepAliveThread->start(); + + TLOGDEBUG("NodeServer::initialize |KeepAliveThread start" << endl); + + _reportMemThread = new ReportMemThread(); + _reportMemThread->start(); + + TLOGDEBUG("NodeServer::initialize |_reportMemThread start" << endl); + + //启动批量发布线程 + PlatformInfo plat; + int iThreads = TC_Common::strto(g_pconf->get("/tars/node", "10")); + + _batchPatchThread = new BatchPatch(); + _batchPatchThread->setPath(plat.getDownLoadDir()); + _batchPatchThread->start(iThreads); + + g_BatchPatchThread = _batchPatchThread; + + TLOGDEBUG("NodeServer::initialize |BatchPatchThread start(" << iThreads << ")" << endl); + + _removeLogThread = new RemoveLogManager(); + _removeLogThread->start(iThreads); + + g_RemoveLogThread = _removeLogThread; + + TLOGDEBUG("NodeServer::initialize |RemoveLogThread start(" << iThreads << ")" << endl); +} + +void NodeServer::initRegistryObj() +{ + string sLocator = Application::getCommunicator()->getProperty("locator"); + vector vtLocator = TC_Common::sepstr(sLocator, "@"); + TLOGDEBUG("locator:" << sLocator << endl); + if (vtLocator.size() == 0) + { + TLOGERROR("NodeServer::initRegistryObj failed to parse locator" << endl); + exit(1); + } + + vector vObj = TC_Common::sepstr(vtLocator[0], "."); + if (vObj.size() != 3) + { + TLOGERROR("NodeServer::initRegistryObj failed to parse locator" << endl); + exit(1); + } + + //获取主控名字的前缀 + string sObjPrefix(""); + string::size_type pos = vObj[2].find("QueryObj"); + if (pos != string::npos) + { + sObjPrefix = vObj[2].substr(0, pos); + } + + AdminProxy::getInstance()->setRegistryObjName("tars.tarsregistry." + sObjPrefix + "RegistryObj", + "tars.tarsregistry." + sObjPrefix + "QueryObj"); + + TLOGDEBUG("NodeServer::initRegistryObj RegistryObj:" << ("tars.tarsregistry." + sObjPrefix + "RegistryObj") << endl); + TLOGDEBUG("NodeServer::initRegistryObj QueryObj:" << ("tars.tarsregistry." + sObjPrefix + "QueryObj") << endl); +} + +void NodeServer::initHashMap() +{ + TLOGDEBUG("NodeServer::initHashMap " << endl); + + string sFile = ServerConfig::DataPath + "/" + g_pconf->get("/tars/node/hashmap", "__tarsnode_servers"); + string sPath = TC_File::extractFilePath(sFile); + int iMinBlock = TC_Common::strto(g_pconf->get("/tars/node/hashmap", "500")); + int iMaxBlock = TC_Common::strto(g_pconf->get("/tars/node/hashmap", "500")); + float iFactor = TC_Common::strto(g_pconf->get("/tars/node/hashmap", "1")); + int iSize = TC_Common::toSize(g_pconf->get("/tars/node/hashmap"), 1024 * 1024 * 10); + + if (!TC_File::makeDirRecursive(sPath)) + { + TLOGDEBUG("NodeServer::initHashMap cannot create hashmap file " << sPath << endl); + exit(0); + } + + try + { + g_serverInfoHashmap.initDataBlockSize(iMinBlock, iMaxBlock, iFactor); + g_serverInfoHashmap.initStore(sFile.c_str(), iSize); + + TLOGDEBUG("NodeServer::initHashMap init hash map succ" << endl); + } + catch (TC_HashMap_Exception& e) + { + TC_File::removeFile(sFile, false); + runtime_error(e.what()); + } +} + +TC_Endpoint NodeServer::getAdapterEndpoint(const string& name) const +{ + TLOGINFO("NodeServer::getAdapterEndpoint:" << name << endl); + + TC_EpollServerPtr pEpollServerPtr = Application::getEpollServer(); + assert(pEpollServerPtr); + + TC_EpollServer::BindAdapterPtr pBindAdapterPtr = pEpollServerPtr->getBindAdapter(name); + assert(pBindAdapterPtr); + + return pBindAdapterPtr->getEndpoint(); +} + +bool NodeServer::cmdViewServerDesc(const string& command, const string& params, string& result) +{ + TLOGINFO("NodeServer::cmdViewServerDesc" << command << " " << params << endl); + + vector v = TC_Common::sepstr(params, "."); + if (v.size() != 2) + { + result = "invalid params:" + params; + return false; + } + + string application = v[0]; + string serverName = v[1]; + + ServerObjectPtr pServerObjectPtr = ServerFactory::getInstance()->getServer(application, serverName); + if (pServerObjectPtr) + { + ostringstream os; + pServerObjectPtr->getServerDescriptor().display(os); + result = os.str(); + return false; + } + + result = "server " + params + " not exist"; + + return true; +} + +bool NodeServer::cmdReLoadConfig(const string& command, const string& params, string& result) +{ + TLOGDEBUG("NodeServer::cmdReLoadConfig " << endl); + + bool bRet = false; + + if (addConfig("tarsnode.conf")) + { + bRet = ServerFactory::getInstance()->loadConfig(); + } + + string s = bRet ? "OK" : "failure"; + + result = "cmdReLoadConfig " + s; + + return bRet; +} + +void NodeServer::destroyApp() +{ + if (_keepAliveThread) + { + delete _keepAliveThread; + _keepAliveThread = NULL; + } + + if (_reportMemThread) + { + delete _reportMemThread; + _reportMemThread = NULL; + } + + if (_batchPatchThread) + { + delete _batchPatchThread; + _batchPatchThread = NULL; + } + + if (_removeLogThread) + { + delete _removeLogThread; + _removeLogThread = NULL; + } + + TLOGDEBUG("NodeServer::destroyApp "<< pthread_self() << endl); +} + +string tostr(const set& setStr) +{ + string str = "{"; + set::iterator it = setStr.begin(); + int i = 0; + for (; it != setStr.end(); it++, i++) + { + if (i > 0) + { + str += "," + *it; + } + else + { + str += *it; + } + } + str += "}"; + + return str; +} + +bool NodeServer::isValid(const string& ip) +{ + static time_t g_tTime = 0; + static set g_ipSet; + + time_t tNow = TNOW; + + static TC_ThreadLock g_tMutex; + + TC_ThreadLock::Lock lock(g_tMutex); + if (tNow - g_tTime > 60) + { + string objs = g_pconf->get("/tars/node", "tars.tarsregistry.AdminRegObj:tars.tarsAdminRegistry.AdminRegObj"); + string ips = g_pconf->get("/tars/node", "172.25.38.208:172.25.38.208"); + + TLOGDEBUG("NodeServer::isValid objs:" << objs << "|ips:" << ips << endl); + + vector vObj = TC_Common::sepstr(objs, ":"); + + vector vIp = TC_Common::sepstr(ips, ":"); + for (size_t i = 0; i < vIp.size(); i++) + { + g_ipSet.insert(vIp[i]); + TLOGDEBUG(ips << "g_ipSet insert ip:" << vIp[i] << endl); + } + + for (size_t i = 0; i < vObj.size(); i++) + { + set tempSet; + string obj = vObj[i]; + try + { + + QueryFPrx queryPrx = Application::getCommunicator()->stringToProxy(obj); + vector vActiveEp, vInactiveEp; + queryPrx->tars_endpointsAll(vActiveEp, vInactiveEp); + + for (unsigned i = 0; i < vActiveEp.size(); i++) + { + tempSet.insert(vActiveEp[i].host()); + } + + for (unsigned i = 0; i < vInactiveEp.size(); i++) + { + tempSet.insert(vInactiveEp[i].host()); + } + + TLOGDEBUG("NodeServer::isValid "<< obj << "|tempSet.size():" << tempSet.size() << "|" << tostr(tempSet) << endl); + } + catch (exception& e) + { + TLOGERROR("NodeServer::isValid catch error: " << e.what() << endl); + } + catch (...) + { + TLOGERROR("NodeServer::isValid catch error: " << endl); + } + + if (tempSet.size() > 0) + { + g_ipSet.insert(tempSet.begin(), tempSet.end()); + } + } + + TLOGDEBUG("NodeServer::isValid g_ipSet.size():" << g_ipSet.size() << "|" << tostr(g_ipSet) << endl); + g_tTime = tNow; + } + + if (g_ipSet.count(ip) > 0) + { + return true; + } + + if (g_sNodeIp == ip) + { + return true; + } + + return false; +} + +void NodeServer::reportServer(const string& sServerId, const string& sResult) +{ + try + { + //上报到notify + NotifyPrx pNotifyPrx = Application::getCommunicator()->stringToProxy(ServerConfig::Notify); + if (pNotifyPrx && sResult != "") + { + pNotifyPrx->async_reportServer(NULL, sServerId, "", sResult); + } + } + catch (exception& ex) + { + TLOGERROR("NodeServer::reportServer error:" << ex.what() << endl); + } +} diff --git a/NodeServer/NodeServer.h b/NodeServer/NodeServer.h new file mode 100644 index 00000000..a9d89754 --- /dev/null +++ b/NodeServer/NodeServer.h @@ -0,0 +1,103 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __NODE_SERVER_H_ +#define __NODE_SERVER_H_ + +#include "servant/Application.h" +#include "KeepAliveThread.h" +#include "ReportMemThread.h" +#include "QueryF.h" +#include "BatchPatchThread.h" +#include "RemoveLogThread.h" +#include "util.h" + +using namespace tars; + +const string NODE_VERSION="B001"; + +class NodeServer; + +extern NodeServer g_app; + +class NodeServer : public Application +{ +public: + /** + * 获取Adapter Endpoint + */ + TC_Endpoint getAdapterEndpoint(const string& name ) const; + + /** + * 添加Config + * @param filename + */ + bool addConfig(const string &filename){return Application::addConfig(filename);} + + /* + * 权限控制 + */ + bool isValid(const string& ip); + + /* + * 上报string至notify + */ + void reportServer(const string &sServerId,const string &sResult); + +public: + /* + * 管理指令 + */ + bool cmdViewServerDesc(const string& command, const string& params, string& result); + /** + *@brief 加载服务配置文件,并使之生效 + * + */ + bool cmdReLoadConfig(const string& command, const string& params, string& result); + +protected: + + /** + * 初始化, 只会进程调用一次 + */ + virtual void initialize(); + + /** + * 析够, 只会进程调用一次 + */ + virtual void destroyApp(); + + /** + * 初始化hashmap + */ + void initHashMap(); +private: + /** + *初始化主控obj名字 + */ + void initRegistryObj(); +private: + KeepAliveThread * _keepAliveThread; + ReportMemThread * _reportMemThread; + + BatchPatch * _batchPatchThread; + RemoveLogManager * _removeLogThread; + + static string g_sNodeIp; +}; +#endif + + diff --git a/NodeServer/PlatformInfo.cpp b/NodeServer/PlatformInfo.cpp new file mode 100644 index 00000000..855e3425 --- /dev/null +++ b/NodeServer/PlatformInfo.cpp @@ -0,0 +1,116 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "PlatformInfo.h" +#include "util/tc_clientsocket.h" +#include "NodeServer.h" + +NodeInfo PlatformInfo::getNodeInfo() const +{ + NodeInfo tNodeInfo; + tNodeInfo.nodeName = getNodeName(); + tNodeInfo.dataDir = getDataDir(); + TC_Endpoint tEndPoint = g_app.getAdapterEndpoint("NodeAdapter"); + tNodeInfo.nodeObj = ServerConfig::Application + "." + ServerConfig::ServerName + ".NodeObj@" + tEndPoint.toString(); + tNodeInfo.endpointIp = tEndPoint.getHost(); + tNodeInfo.endpointPort = tEndPoint.getPort(); + tNodeInfo.timeOut = tEndPoint.getTimeout(); + tNodeInfo.version = TARS_VERSION+string("_")+NODE_VERSION; + + return tNodeInfo; +} + +LoadInfo PlatformInfo::getLoadInfo() const +{ + LoadInfo info; + info.avg1 = -1.0f; + info.avg5 = -1.0f; + info.avg15 = -1.0f; + + double loadAvg[3]; + if ( getloadavg( loadAvg, 3 ) != -1 ) + { + info.avg1 = static_cast( loadAvg[0] ); + info.avg5 = static_cast( loadAvg[1] ); + info.avg15 = static_cast( loadAvg[2] ); + } + + return info; +} + +string PlatformInfo::getNodeName() const +{ + return ServerConfig::LocalIp; +} + +string PlatformInfo::getDataDir() const +{ + string sDataDir; + sDataDir = ServerConfig::DataPath; + + if ( TC_File::isAbsolute(sDataDir) == false) + { + char cwd[PATH_MAX]; + if ( getcwd( cwd, PATH_MAX ) == NULL ) + { + TLOGERROR("PlatformInfo::getDataDir cannot get the current directory:\n" << endl); + exit( 0 ); + } + sDataDir = string(cwd) + '/' + sDataDir; + } + + sDataDir = TC_File::simplifyDirectory(sDataDir); + if ( sDataDir[sDataDir.length() - 1] == '/' ) + { + sDataDir = sDataDir.substr( 0, sDataDir.length() - 1 ); + } + + return sDataDir; +} + +string PlatformInfo::getDownLoadDir() const +{ + string sDownLoadDir = ""; + try + { + sDownLoadDir = g_app.getConfig().get("/tars/node",""); + if(sDownLoadDir == "") + { + string sDataDir = getDataDir(); + string::size_type pos = sDataDir.find_last_of("/"); + if(pos != string::npos) + { + sDownLoadDir = sDataDir.substr(0,pos)+"/tmp/download/"; + } + } + + sDownLoadDir = TC_File::simplifyDirectory(sDownLoadDir); + if(!TC_File::makeDirRecursive( sDownLoadDir )) + { + TLOGERROR("getDownLoadDir property `tars/node' is not set and cannot create dir:"< +#include "util/tc_config.h" +#include +#include "servant/Application.h" + +using namespace tars; +using namespace std; + +extern TC_Config* g_pconf; + +class PlatformInfo +{ +public: + /** + * 获取node的相关信息 + */ + NodeInfo getNodeInfo() const; + + /** + * 获取node的所在机器的负载信息 + */ + LoadInfo getLoadInfo() const; + + /** + * 获取node的名称 + */ + string getNodeName() const; + + /** + * 获取node的数据目录 + */ + string getDataDir() const; + + /** + * 获取文件下载目录 + */ + string getDownLoadDir() const; +}; + +#endif + diff --git a/NodeServer/PropertyReporter.h b/NodeServer/PropertyReporter.h new file mode 100644 index 00000000..3b725906 --- /dev/null +++ b/NodeServer/PropertyReporter.h @@ -0,0 +1,63 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __PropertyReporter_H_ +#define __PropertyReporter_H_ + + +#include "servant/Application.h" + +//eg1: REPORT_COUNT("socket_error", 1); +//eg2: REPORT_SUM("GB_consume", 100); + + +//define reporter template +#define REPORT_INSTALL \ +template \ +PropertyReportPtr creatReport(const string & master, string msg, REPORTFUNC reportFunc) \ +{ \ + PropertyReportPtr srp = Application::getCommunicator()->getStatReport()->getPropertyReport(msg); \ + if ( !srp ) \ + { \ + srp = Application::getCommunicator()->getStatReport()->createPropertyReport(msg, reportFunc); \ + srp->setMasterName(master);\ + } \ + return srp; \ +}; + + +//count report +#define REPORT_COUNT(master, str,value) \ +PropertyReportPtr countReporter = creatReport(master, str, PropertyReport::count()); \ +countReporter->report(value); + + +//sum report +#define REPORT_SUM(master, str,value) \ +PropertyReportPtr sumReporter = creatReport(master, str, PropertyReport::sum()); \ +sumReporter->report(value); + +//max report +#define REPORT_MAX(master, str,value) \ +PropertyReportPtr maxReporter = creatReport(master, str, PropertyReport::max()); \ +maxReporter->report(value); + +//set a reporter +REPORT_INSTALL; + + +#endif // __PropertyReporter_H_ + diff --git a/NodeServer/RegistryProxy.h b/NodeServer/RegistryProxy.h new file mode 100644 index 00000000..9c5eb2f1 --- /dev/null +++ b/NodeServer/RegistryProxy.h @@ -0,0 +1,73 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __REGISTRY_PROXY_H_ +#define __REGISTRY_PROXY_H_ + +#include "Node.h" +#include "ServerFactory.h" +#include "util/tc_config.h" +#include "QueryF.h" +#include "servant/Communicator.h" +#include "util/tc_singleton.h" +#include "NodeServer.h" + +using namespace tars; +using namespace std; + +class AdminProxy; + +class AdminProxy : public TC_Singleton +{ +public: + RegistryPrx getRegistryProxy() + { + RegistryPrx pRistryPrx; + string sRegistry = g_app.getConfig().get("/tars/node",_registryProxyName); + + Application::getCommunicator()->stringToProxy(sRegistry, pRistryPrx); + + return pRistryPrx; + } + + QueryFPrx getQueryProxy() + { + QueryFPrx pQueryPrx; + string sQuery = g_app.getConfig().get("/tars/node", _queryProxyName); + + Application::getCommunicator()->stringToProxy(sQuery, pQueryPrx); + + return pQueryPrx; + } + + inline void setRegistryObjName(const string &sRegistryProxyName, const string &sQueryProxyName) + { + _registryProxyName = sRegistryProxyName; + _queryProxyName = sQueryProxyName; + } + + inline string& getRegistryProxyName(){ return _registryProxyName; } + + inline string& getQueryProxyName() { return _queryProxyName; } + +private: + + string _registryProxyName; + string _queryProxyName; +}; +#endif + + diff --git a/NodeServer/RemoveLogThread.cpp b/NodeServer/RemoveLogThread.cpp new file mode 100644 index 00000000..e5857107 --- /dev/null +++ b/NodeServer/RemoveLogThread.cpp @@ -0,0 +1,172 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "util/tc_md5.h" +#include "RemoveLogThread.h" +#include "ServerFactory.h" +#include "NodeRollLogger.h" +#include "util/tc_timeprovider.h" +#include "util.h" + +using namespace tars; + +RemoveLogManager::RemoveLogManager() +{ +} + +RemoveLogManager::~RemoveLogManager() +{ + terminate(); +} + +void RemoveLogManager::start(int iNum) +{ + for (int i = 0; i < iNum; i++) + { + RemoveLogThread * t = new RemoveLogThread(this); + t->start(); + + _runners.push_back(t); + } +} + +void RemoveLogManager::terminate() +{ + for (size_t i = 0; i < _runners.size(); ++i) + { + if(_runners[i]->isAlive()) + { + _runners[i]->terminate(); + } + } + + for (size_t i = 0; i < _runners.size(); ++i) + { + if(_runners[i]->isAlive()) + { + _runners[i]->getThreadControl().join(); + } + } + + _queueMutex.notifyAll(); +} + +int RemoveLogManager::push_back(const string& logPath) +{ + { + TC_ThreadLock::Lock LockQueue(_queueMutex); + + if (_reqSet.count(logPath) == 1) + { + return -1; + } + + _reqQueue.push_back(logPath); + _reqSet.insert(logPath); + } + + return 0; +} + +bool RemoveLogManager::pop_front(string& logPath) +{ + TC_ThreadLock::Lock LockQueue(_queueMutex); + + bool bRet=false; + + bRet=_reqQueue.pop_front(logPath); + + if(bRet) + { + _reqSet.erase(logPath); + } + + return bRet; +} + +void RemoveLogManager::timedWait(int millsecond) +{ + TC_ThreadLock::Lock lock(_queueMutex); + + _queueMutex.timedWait(millsecond); +} + +///////////////////////////////////////// +RemoveLogThread::RemoveLogThread(RemoveLogManager * manager) +: _manager(manager) +, _shutDown(false) +{ +} + +RemoveLogThread::~RemoveLogThread() +{ + terminate(); +} + +void RemoveLogThread::terminate() +{ + _shutDown = true; + + if (isAlive()) + { + getThreadControl().join(); + } +} + +void RemoveLogThread::run() +{ + while (!_shutDown) + { + try + { + string sLogPath; + if (_manager->pop_front(sLogPath)) + { + int64_t startMs = TC_TimeProvider::getInstance()->getNowMs(); + if (TC_File::isFileExistEx(sLogPath, S_IFDIR)) + { + int ret = TC_File::removeFile(sLogPath,true); + if (ret == 0) + { + NODE_LOG("RemoveLogThread")->debug() <getNowMs() - startMs) << endl; + } + else + { + NODE_LOG("RemoveLogThread")->error()<getNowMs() - startMs) << endl; + } + } + else + { + NODE_LOG("RemoveLogThread")->debug()<getNowMs() - startMs) << endl; + } + } + else + { + _manager->timedWait(2000); + } + + } + catch (exception& e) + { + NODE_LOG("RemoveLogThread")->error()<error()< _reqQueue; + + std::set _reqSet; //用于去重 + + std::vector _runners; +}; + +class RemoveLogThread : public TC_Thread +{ +public: + RemoveLogThread(RemoveLogManager * manager); + + ~RemoveLogThread(); + + virtual void run(); + + void terminate(); + +protected: + RemoveLogManager * _manager; + + bool _shutDown; +}; + +#endif diff --git a/NodeServer/ReportMemThread.cpp b/NodeServer/ReportMemThread.cpp new file mode 100644 index 00000000..f5e4353c --- /dev/null +++ b/NodeServer/ReportMemThread.cpp @@ -0,0 +1,108 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "ReportMemThread.h" +#include "RegistryProxy.h" +#include "NodeRollLogger.h" +#include "util/tc_timeprovider.h" +#include "util.h" + +ReportMemThread::ReportMemThread( ) +{ + _shutDown = false; + //用旧配置 + _monitorInterval = TC_Common::strto(g_pconf->get("/tars/node/keepalive","2")); + _monitorInterval = _monitorInterval>10?10:(_monitorInterval<1?1:_monitorInterval); +} + +ReportMemThread::~ReportMemThread() +{ + terminate(); +} + +void ReportMemThread::terminate() +{ + NODE_LOG("ReportMemThread")->debug()<error()<error()< mmServerList = ServerFactory::getInstance()->getAllServers(); + map::const_iterator it = mmServerList.begin(); + for(;it != mmServerList.end(); it++) + { + map::const_iterator p = it->second.begin(); + for(;p != it->second.end(); p++) + { + try + { + sServerId = it->first+"."+p->first; + ServerObjectPtr pServerObjectPtr = p->second; + if(!pServerObjectPtr) + { + NODE_LOG("ReportMemThread")->debug()<reportMemProperty(); + + } + catch(exception &e) + { + NODE_LOG("ReportMemThread")->error()< +#include "ServerFactory.h" +#include "util/tc_monitor.h" +#include "util/tc_thread.h" + +using namespace tars; +using namespace std; + +class ReportMemThread : public TC_Thread//,public TC_ThreadLock +{ +public: + /** + * 构造函数 + */ + ReportMemThread(); + + /** + * 析构函数 + */ + ~ReportMemThread(); + + /** + * 结束线程 + */ + void terminate(); + +protected: + + virtual void run(); + + void report(); + + bool timedWait(int millsecond); + +protected: + + bool _shutDown; + int _monitorInterval; + TC_ThreadLock _lock; +}; + + +#endif + diff --git a/NodeServer/ServerCommand.h b/NodeServer/ServerCommand.h new file mode 100644 index 00000000..33c6a87d --- /dev/null +++ b/NodeServer/ServerCommand.h @@ -0,0 +1,109 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __SERVER_COMMAND_H_ +#define __SERVER_COMMAND_H_ + +#include "ServerObject.h" +#include "NodeServer.h" + +class StatExChange; + +typedef TC_AutoPtr StatExChangePtr; + +class ServerCommand : public TC_HandleBase +{ +public: + enum ExeStatus + { + EXECUTABLE, //可以运行 + DIS_EXECUTABLE, //不可以运行 + NO_NEED_EXECUTE //不需要运行 + }; +public: + virtual ~ServerCommand(){} + + virtual ExeStatus canExecute(string &sResult){ return EXECUTABLE;} + + virtual int execute(string &sResult) = 0; + + virtual int doProcess() + { + string s ; + return doProcess(s); + } + + virtual int doProcess(string &sResult) + { + ExeStatus t = canExecute(sResult); + if(t == DIS_EXECUTABLE) + { + return -1; + } + else if(t == NO_NEED_EXECUTE) + { + return 0; + } + + return execute(sResult); + } + + virtual int doProcess(const TarsCurrentPtr current,string &sResult, bool bValid=true) + { + if( bValid && g_app.isValid(current->getIp()) == false ) + { + sResult = " erro:ip "+ current->getIp()+" is invalid"; + return -1; + } + + return doProcess(sResult); + } +}; + + +class StatExChange : public TC_HandleBase +{ +public: + + /** + * 构造函数 + * @param pServerObjectPtr ServerObject指针 + * @param eState1 状态1,构造时设置pServerObjectPtr 状态为state1 + * @param eState2 状态2,析构时设置pServerObjectPtr 状态为state2 + */ + StatExChange( const ServerObjectPtr& pServerObjectPtr, ServerObject::InternalServerState eState1, ServerObject::InternalServerState eState2 ) + { + _serverObjectPtr = pServerObjectPtr; + _state1 = eState1; + _state2 = eState2; + _serverObjectPtr->setState( _state1 ); + } + + /** + * 析够 + */ + ~StatExChange() + { + _serverObjectPtr->setState( _state2 ); + } + +private: + ServerObject::InternalServerState _state1; + ServerObject::InternalServerState _state2; + ServerObjectPtr _serverObjectPtr; +}; + +#endif diff --git a/NodeServer/ServerFactory.cpp b/NodeServer/ServerFactory.cpp new file mode 100644 index 00000000..ad3c6b68 --- /dev/null +++ b/NodeServer/ServerFactory.cpp @@ -0,0 +1,480 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "ServerFactory.h" +#include "RegistryProxy.h" +#include "CommandLoad.h" +#include "NodeRollLogger.h" + +HashMap g_serverInfoHashmap; + +ServerFactory::ServerFactory() +: _bReousceLimitConfChanged(false) +, _iMinMonitorIntervalMs(60000) +, _bReportLoadInfo(true) +{ +} + +ServerObjectPtr ServerFactory::getServer( const string& application, const string& serverName ) +{ + TLOGINFO("ServerFactory::getServer: "<::const_iterator p1 = _mmServerList.find( application ); + if ( p1 != _mmServerList.end() ) + { + map::const_iterator p2 = p1->second.find( serverName ); + if ( p2 != p1->second.end() && p2->second ) + { + return p2->second; + } + } + return NULL; +} + +int ServerFactory::eraseServer( const string& application, const string& serverName ) +{ + Lock lock( *this ); + + map::const_iterator p1 = _mmServerList.find( application ); + if ( p1 == _mmServerList.end() ) + { + return 0; + } + + map::const_iterator p2 = p1->second.find( serverName ); + if ( p2 == p1->second.end() ) + { + return 0; + } + + _mmServerList[application].erase( serverName ); + if ( p1->second.empty() ) + { + _mmServerList.erase( application ); + } + + return 0; +} + +ServerObjectPtr ServerFactory::loadServer( const string& application, const string& serverName,bool enableCache,string& result) +{ + ServerObjectPtr pServerObjectPtr; + vector vServerDescriptor; + + vServerDescriptor = getServerFromRegistry(application,serverName,result); + + //全量加载失败后从cache里面读取 + if(vServerDescriptor.size() < 1 && enableCache == true) + { + vServerDescriptor = getServerFromCache(application,serverName,result); + } + + if(vServerDescriptor.size() < 1) + { + result += " cannot load server description from regisrty "; + return NULL; + } + + for(unsigned i = 0; i < vServerDescriptor.size(); i++) + { + pServerObjectPtr = createServer(vServerDescriptor[i],result); + } + + return pServerObjectPtr; +} + +vector ServerFactory::getServerFromRegistry( const string& application, const string& serverName, string& result) +{ + TLOGDEBUG("ServerFactory::getServerFromRegistry"< vServerDescriptor; + try + { + RegistryPrx _pRegistryPrx = AdminProxy::getInstance()->getRegistryProxy(); + + if(!_pRegistryPrx) + { + TLOGERROR("ServerFactory::getServerFromRegistry cann't get the proxy of registry. "<getServers( application, serverName, _tPlatformInfo.getNodeName()); + //清空cache + if( vServerDescriptor.size()> 0 && application == "" && serverName == "") + { + g_serverInfoHashmap.clear(); + TLOGINFO("ServerFactory::getServerFromRegistry hashmap clear ok "< ServerFactory::getServerFromCache( const string& application, const string& serverName, string& result) +{ + TLOGDEBUG("ServerFactory::getServerFromCache: "<< application <<"."< vServerDescriptor; + if(application != "" && serverName != "") + { + tServerInfo.application = application; + tServerInfo.serverName = serverName; + if(g_serverInfoHashmap.get(tServerInfo,tServerDescriptor) == TC_HashMap::RT_OK) + { + vServerDescriptor.push_back(tServerDescriptor); + } + } + else + { + HashMap::lock_iterator it = g_serverInfoHashmap.beginSetTime(); + while(it != g_serverInfoHashmap.end()) + { + ServerInfo tServerInfo; + ServerDescriptor tServerDescriptor; + int ret = it->get(tServerInfo,tServerDescriptor); + if(ret != TC_HashMap::RT_OK) + { + result =result + "\n hashmap erro:"+TC_Common::tostr(ret); + TLOGERROR("ServerFactory::getServerFromCache "<::const_iterator p1 = _mmServerList.find( application ); + if ( p1 != _mmServerList.end() ) + { + map::const_iterator p2 = p1->second.find( serverName ); + if ( p2 != p1->second.end() && p2->second ) + { + p2->second->setServerDescriptor(tDesc); + CommandLoad command(p2->second,_tPlatformInfo.getNodeInfo()); + int iRet = command.doProcess(result); + if( iRet == 0) + { + return p2->second; + } + else + { + return NULL; + } + } + } + + ServerObjectPtr pServerObjectPtr = new ServerObject(tDesc); + CommandLoad command(pServerObjectPtr,_tPlatformInfo.getNodeInfo()); + int iRet = command.doProcess(result); + if(iRet ==0) + { + ServerObject::ServerLimitInfo tInfo; + loadLimitInfo(application, pServerObjectPtr->getServerId(), tInfo); + pServerObjectPtr->setServerLimitInfo(tInfo); + + if(tInfo.iMonitorIntervalMs < _iMinMonitorIntervalMs) + { + NODE_LOG("KeepAliveThread")->debug() <" << tInfo.iMonitorIntervalMs << "|" << pServerObjectPtr->getServerId() << endl; + _iMinMonitorIntervalMs = tInfo.iMonitorIntervalMs; + } + + if (!tInfo.bReportLoadInfo) + { + NODE_LOG("KeepAliveThread")->debug() <getServerId()< ServerFactory::getAllServers() +{ + Lock lock( *this ); + return _mmServerList; +} + +bool ServerFactory::loadConfig() +{ + try + { + //首先取默认配置 + string sDefault="/tars/app_conf/default"; + map m = g_pconf->getDomainMap(sDefault); + parseLimitInfo(m, _defaultLimitInfo,true); + NODE_LOG("KeepAliveThread")->debug()< v = g_pconf->getDomainVector("/tars/app_conf/"); + + map& appConfig = _mAppCoreConfig.getWriterData(); + for(size_t i = 0; i < v.size(); i++) + { + string path = "/tars/app_conf/" + v[i]; + TLOGDEBUG("ServerFactory::loadConfig path:" << path << endl); + map m = g_pconf->getDomainMap(path); + if(v[i] == "default") + { + continue; + } + else + { + ServerObject::ServerLimitInfo limitInfo; + parseLimitInfo(m, limitInfo,false); + + limitInfo.bCloseCore = false; + limitInfo.eCoreType = ServerObject::EM_AUTO_LIMIT; + + vector apps = TC_Common::sepstr(g_pconf->get(string("/tars/app_conf<") +v[i]+ ">",""),"|"); + for(size_t i = 0; i < apps.size(); i++) + { + string app = apps[i]; + appConfig[app] = limitInfo; + } + } + } + _mAppCoreConfig.swap(); + + vector vCloseCoreSrvs = TC_Common::sepstr(g_pconf->get("/tars/app_conf",""),"|"); + vector::const_iterator it = vCloseCoreSrvs.begin(); + + map& serverConfig = _mServerCoreConfig.getWriterData(); + for(;it != vCloseCoreSrvs.end();it++) + { + ServerObject::ServerLimitInfo tInfo = _defaultLimitInfo; + tInfo.bCloseCore = true; + tInfo.eCoreType = ServerObject::EM_MANUAL_LIMIT; + + serverConfig[*it] = tInfo; + TLOGDEBUG("ServerFactory::loadConfig Load ClosecoreLimit:" << *it <& confMap, ServerObject::ServerLimitInfo& limitInfo,bool bDefault) +{ + map::const_iterator it = confMap.find("maxstopcount"); + if(it != confMap.end()) + { + limitInfo.iMaxExcStopCount = TC_Common::strto(it->second); + } + else + { + limitInfo.iMaxExcStopCount=(bDefault ? 3 :_defaultLimitInfo.iMaxExcStopCount); + } + + it = confMap.find("coretimeinterval"); + if(it != confMap.end()) + { + limitInfo.iCoreLimitTimeInterval = TC_Common::strto(it->second); + } + else + { + limitInfo.iCoreLimitTimeInterval = (bDefault ? 5 : _defaultLimitInfo.iCoreLimitTimeInterval); + } + + it = confMap.find("coretimeexpired"); + if(it != confMap.end()) + { + limitInfo.iCoreLimitExpiredTime = TC_Common::strto(it->second); + } + else + { + limitInfo.iCoreLimitExpiredTime =(bDefault ? 30 :_defaultLimitInfo.iCoreLimitExpiredTime); + } + + it = confMap.find("corelimitenable"); + if(it != confMap.end()) + { + limitInfo.bEnableCoreLimit = it->second == "true"; + } + else + { + limitInfo.bEnableCoreLimit = (bDefault ? false :_defaultLimitInfo.bEnableCoreLimit); + } + + it = confMap.find("monitorIntervalMs"); + if(it != confMap.end()) + { + limitInfo.iMonitorIntervalMs = TC_Common::strto(it->second); + } + else + { + limitInfo.iMonitorIntervalMs =(bDefault ? 1000 : _defaultLimitInfo.iMonitorIntervalMs); + } + + it = confMap.find("ActivatorMaxCount"); + if(it != confMap.end()) + { + limitInfo.iActivatorMaxCount = TC_Common::strto(it->second); + } + else + { + limitInfo.iActivatorMaxCount =(bDefault ? 10 : _defaultLimitInfo.iActivatorMaxCount); + } + + it = confMap.find("ActivatorTimeInterval"); + if(it != confMap.end()) + { + limitInfo.iActivatorTimeInterval = TC_Common::strto(it->second); + } + else + { + limitInfo.iActivatorTimeInterval =(bDefault ? 60 : _defaultLimitInfo.iActivatorTimeInterval); + } + + it = confMap.find("ActivatorPunishInterval"); + if(it != confMap.end()) + { + limitInfo.iActivatorPunishInterval = TC_Common::strto(it->second); + } + else + { + limitInfo.iActivatorPunishInterval =(bDefault ? 600 : _defaultLimitInfo.iActivatorPunishInterval); + } + + it=confMap.find("reportLoadInfoenable"); + if (it!=confMap.end()) + { + limitInfo.bReportLoadInfo=TC_Common::strto(it->second)==1 ? true : false; + } + else + { + limitInfo.bReportLoadInfo=(bDefault ? true : _defaultLimitInfo.bReportLoadInfo); + } + +} + +void ServerFactory::setAllServerResourceLimit() +{ + Lock lock( *this ); + + //有更新才加载 + if(_bReousceLimitConfChanged) + { + + map::const_iterator it = _mmServerList.begin(); + for(;it != _mmServerList.end(); it++) + { + map::const_iterator p = it->second.begin(); + for(;p != it->second.end(); p++) + { + string sAppId = it->first; + string sServerId = it->first+"."+p->first; + ServerObjectPtr pServerObjectPtr = p->second; + if(!pServerObjectPtr) + { + continue; + } + + ServerObject::ServerLimitInfo tInfo; + loadLimitInfo(sAppId, sServerId, tInfo); + if(tInfo.iMonitorIntervalMs < _iMinMonitorIntervalMs) + { + NODE_LOG("KeepAliveThread")->debug()<" << tInfo.iMonitorIntervalMs << "|" << sServerId << endl; + _iMinMonitorIntervalMs = tInfo.iMonitorIntervalMs; + } + + TLOGDEBUG("ServerFactory::setAllServerResourceLimit setAllServerResourceLimit|" << sServerId <<"|"<setServerLimitInfo(tInfo); + + } + } + _bReousceLimitConfChanged = false; + } +} + +void ServerFactory::loadLimitInfo(const string& sAppId, const string& sServerId, ServerObject::ServerLimitInfo& tInfo) { + + map& appConfig = _mAppCoreConfig.getReaderData(); + map& serverConfig = _mServerCoreConfig.getReaderData(); + + if(serverConfig.count(sServerId) == 1) + { + tInfo = serverConfig[sServerId]; + } + else if(appConfig.count(sAppId) == 1) + { + tInfo = appConfig[sAppId]; + } + else + { + tInfo = _defaultLimitInfo; + tInfo.bCloseCore = false; + tInfo.eCoreType = ServerObject::EM_AUTO_LIMIT; + } + +} + + diff --git a/NodeServer/ServerFactory.h b/NodeServer/ServerFactory.h new file mode 100644 index 00000000..f26890c9 --- /dev/null +++ b/NodeServer/ServerFactory.h @@ -0,0 +1,201 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __SERVER_FACTORY_H_ +#define __SERVER_FACTORY_H_ +#include "Node.h" +#include +#include "ServerObject.h" +#include "util/tc_common.h" +#include "jmem/jmem_hashmap.h" +#include "util/tc_file.h" +#include "util/tc_singleton.h" +#include "util/tc_readers_writer_data.h" + +using namespace tars; +using namespace std; + +typedef TarsHashMap HashMap; + +extern HashMap g_serverInfoHashmap; + +typedef map ServerGroup; + +class ServerFactory : public TC_Singleton, public TC_ThreadLock +{ +public: + /** + * 构造函数 + */ + ServerFactory(); + + /** + * 析构函数 + */ + ~ServerFactory() + { + }; + + /** + * 创建指定服务 + * @param ServerDescriptor 服务信息 + * @return ServerObjectPtr + */ + ServerObjectPtr createServer( const ServerDescriptor& tDesc) + { + string result; + return createServer(tDesc,result); + } + + /** + * 创建指定服务 + * @param ServerDescriptor 服务信息 + * @param result 结果 + * @return ServerObjectPtr + */ + ServerObjectPtr createServer( const ServerDescriptor& tDesc,string& result); + + /** + * 删除指定服务 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @return int + */ + int eraseServer( const string& application, const string& serverName ); + + /** + * 获取指定服务 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @return ServerObjectPtr 服务不存在返回NULL + */ + ServerObjectPtr getServer( const string& application, const string& serverName ); + + /** + * load服务 若application + * serverName为空load所有服务,只返回最后一个load对象。 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @return ServerObjectPtr 服务不存在返回NULL + */ + ServerObjectPtr loadServer( const string& application="", const string& serverName="",bool enableCache = true) + { + string result; + return loadServer(application,serverName,enableCache,result); + } + + /** + * load服务 若application + * serverName为空load所有服务,只返回最后一个load对象。 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @param result 结果 + * @return ServerObjectPtr 服务不存在返回NULL + */ + ServerObjectPtr loadServer( const string& application, const string& serverName,bool enableCache, string& result); + + /** + * get服务 若application + * serverName为空获取所有服务,只返回最后一个load对象。 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @return vector 服务不存在返回NULL + */ + vector getServerFromRegistry( const string& application, const string& serverName, string& result); + + /** + * get服务 若application + * serverName为空获取所有服务,只返回最后一个load对象。 + * @param application 服务所属应用名 + * @param serverName 服务名 + * @return vector 服务不存在返回NULL + */ + vector getServerFromCache( const string& application, const string& serverName, string& result); + + /** + * 获取node上服务所有服务 + * @return map + */ + map getAllServers(); + + /** + *@brief 加载服务core属性的配置文件 + *@return bool + */ + bool loadConfig(); + + /** + *@brief 设置node上所有服务的core属性,如果node更新过core配置,则不需要设置 + * + */ + void setAllServerResourceLimit(); + + /** + * 获取最小的监控周期 + */ + int32_t getMinMonitorIntervalMs() + { + return _iMinMonitorIntervalMs; + } + + /** + * 是否上报节点负载信息 + */ + bool getReportLoadInfo() {return _bReportLoadInfo;} + +private: + + /** + * 解析node管理服务的limit资源配置 + */ + void parseLimitInfo(const map& confMap, ServerObject::ServerLimitInfo& limitInfo, bool bDefault); + + /** + * 获取服务进程的limit资源配置 + */ + void loadLimitInfo(const string& sAppId, const string& sServerId, ServerObject::ServerLimitInfo& tInfo); + +private: + //> + map _mmServerList; + + PlatformInfo _tPlatformInfo; + +private: + + // + TC_ReadersWriterData > _mServerCoreConfig; + + // + TC_ReadersWriterData > _mAppCoreConfig; + + //配置是否有更新 + bool _bReousceLimitConfChanged; + + //最大服务异常停止个数,超过限制则自动屏蔽coredump + ServerObject::ServerLimitInfo _defaultLimitInfo; + + //最小的监控周期 + int32_t _iMinMonitorIntervalMs; + + //是否上报节点负载信息,默认上报 + bool _bReportLoadInfo; +}; + + +#endif + + diff --git a/NodeServer/ServerImp.cpp b/NodeServer/ServerImp.cpp new file mode 100644 index 00000000..eacdba04 --- /dev/null +++ b/NodeServer/ServerImp.cpp @@ -0,0 +1,79 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "ServerImp.h" +#include "util.h" + +int ServerImp::keepAlive( const tars::ServerInfo& serverInfo, tars::TarsCurrentPtr current ) +{ + try + { + string sApp = serverInfo.application; + string sName = serverInfo.serverName; + + ServerObjectPtr pServerObjectPtr = ServerFactory::getInstance()->getServer( sApp, sName ); + if(pServerObjectPtr) + { + TLOGDEBUG("ServerImp::keepAlive server " << serverInfo.application << "." << serverInfo.serverName << " keep alive"<< endl); + + pServerObjectPtr->keepAlive(serverInfo.pid,serverInfo.adapter); + + return 0; + } + + TLOGDEBUG("ServerImp::keepAlive server " << serverInfo.application << "." << serverInfo.serverName << " is not exist"<< endl); + } + catch ( exception& e ) + { + TLOGERROR( "ServerImp::keepAlive catch exception :" << e.what() << endl); + } + catch ( ... ) + { + TLOGERROR("ServerImp::keepAlive unkown exception catched" << endl); + } + + return -1; +} + +int ServerImp::reportVersion( const string &app,const string &serverName,const string &version,tars::TarsCurrentPtr current) +{ + try + { + TLOGDEBUG("ServerImp::reportVersion|server|" << app << "." << serverName << "|version|" << version<< endl); + + ServerObjectPtr pServerObjectPtr = ServerFactory::getInstance()->getServer( app, serverName ); + if(pServerObjectPtr) + { + pServerObjectPtr->setVersion(version); + + return 0; + } + + TLOGDEBUG("ServerImp::reportVersion server " << app << "." << serverName << " is not exist"<< endl); + } + catch ( exception& e ) + { + TLOGERROR("ServerImp::reportVersion catch exception :" << e.what() << endl); + } + catch ( ... ) + { + TLOGERROR("ServerImp::reportVersion unkown exception catched" << endl); + } + + return -1; +} + + diff --git a/NodeServer/ServerImp.h b/NodeServer/ServerImp.h new file mode 100644 index 00000000..61517b0f --- /dev/null +++ b/NodeServer/ServerImp.h @@ -0,0 +1,77 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __SERVER_IMP_H_ +#define __SERVER_IMP_H_ +#include "Node.h" +#include +#include "ServerFactory.h" +#include "util/tc_common.h" + + + +using namespace tars; +using namespace std; + +class ServerImp : public ServerF +{ +public: + /** + * 构造函数 + */ + ServerImp() + { + } + + + /** + * 析构函数 + */ + virtual ~ServerImp() + { + } + + /** + * 初始化 + */ + virtual void initialize() + { + }; + + /** + * 退出 + */ + virtual void destroy() + { + }; + + /** + * 上报心跳 + */ + virtual int keepAlive( const tars::ServerInfo& serverInfo, tars::TarsCurrentPtr current ) ; + + /** + * 上报tars版本 + */ + virtual int reportVersion( const string &app,const string &serverName,const string &version,tars::TarsCurrentPtr current) ; + +private: +}; + +typedef TC_AutoPtr ServerImpPtr; + +#endif + diff --git a/NodeServer/ServerLimitResource.cpp b/NodeServer/ServerLimitResource.cpp new file mode 100644 index 00000000..460a757b --- /dev/null +++ b/NodeServer/ServerLimitResource.cpp @@ -0,0 +1,111 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "ServerLimitResource.h" +#include "util/tc_timeprovider.h" +#include "servant/TarsLogger.h" +#include "NodeRollLogger.h" +#include "util.h" + +ServerLimitResource::ServerLimitResource( int iMaxCount,int iTimeInterval/*分钟*/ ,int iExpiredTime/*分钟*/,const string& app,const string& servername) +: _maxExcStopCount(iMaxCount) +, _coreLimitTimeInterval(iTimeInterval*60) +, _coreLimitExpiredTime(iExpiredTime*60) +, _appName(app) +, _serverName(servername) +{ + resetRunTimeData(); +} + +void ServerLimitResource::resetRunTimeData() +{ + time_t tNow = TNOW; + _closeCore = false; + _curExcStopCount = 0; + _excStopRecordTime = tNow; + _enableCoreLimitTime = 0; +} + +void ServerLimitResource::setLimitCheckInfo(int iMaxCount,int iTimeInterval,int iExpiredTime) +{ + TC_ThreadLock::Lock lock(*this); + _maxExcStopCount = (iMaxCount>0)?iMaxCount:1; + _coreLimitTimeInterval = (iTimeInterval>0?iTimeInterval:1)*60; + _coreLimitExpiredTime = (iExpiredTime>0?iExpiredTime:1)*60; +} + +void ServerLimitResource::addExcStopRecord() +{ + time_t tNow = TNOW; + + TC_ThreadLock::Lock lock(*this); + //在允许的时间段内才检查是否增加计数和关闭core属性 + NODE_LOG("core")->debug() << FILE_FUN<< (_appName+"."+_serverName) << "|before|" << tNow << "|" << _excStopRecordTime + << "|" << _coreLimitTimeInterval << "|" << _curExcStopCount << "|" << _closeCore << "|" << _maxExcStopCount << endl; + if((tNow - _excStopRecordTime) < _coreLimitTimeInterval) + { + _curExcStopCount++; + if(!_closeCore && (_curExcStopCount >= _maxExcStopCount)) + { + _closeCore = true; + _enableCoreLimitTime = tNow; + } + } + else + { + //重新计数 + _curExcStopCount = 1; + _excStopRecordTime = tNow; + } + NODE_LOG("core")->debug() << FILE_FUN << (_appName+"."+_serverName) << "|after|" << tNow << "|" << _excStopRecordTime + << "|" << _coreLimitTimeInterval << "|" << _curExcStopCount << "|" << _closeCore << "|" << _maxExcStopCount << endl; +} + +int ServerLimitResource::IsCoreLimitNeedClose(bool& bClose) +{ + time_t tNow = TNOW; + + int ret = 0; + if(_closeCore) + { + if((tNow -_enableCoreLimitTime) < _coreLimitExpiredTime) + { + bClose = true; + ret = 1; + } + //如果core屏蔽过期,则重新打开 + else + { + TC_ThreadLock::Lock lock(*this); + NODE_LOG("core")->debug() <debug() < +#include +#include "util/tc_monitor.h" +#include "util/tc_autoptr.h" + +using namespace tars; +using namespace std; + +class ServerLimitResource : public TC_ThreadLock, public TC_HandleBase +{ +public: + + ServerLimitResource(int iMaxCount=3,int iTimeInterval=5/*分钟*/,int iExpiredTime=30/*分钟*/,const string& app="",const string& servername=""); + + ~ServerLimitResource(){} + +public: + void setLimitCheckInfo(int iMaxCount,int iTimeInterval,int iExpiredTime); + /** + * @brief 服务异常重启记录 + * + *1 如果在_coreLimitTimeInterval时间段内,则增加异常个数 + *2 判断异常个数,如果在时间段内达到core限制_maxExcStopCount,则屏蔽core属性_closeCore + * 并记录当前时间戳_enableCoreLimitTime + */ + void addExcStopRecord(); + /** + *@brief 检查是否需要关闭或者打开core + * + *1 如果服务core被关闭,则先检查被关闭的时间戳,如果过期,且本服务没有配置manual关闭,则打开core属性 + *2 检查core开关,如果true则关闭core,则异步通知服务关闭,否则打开开关 + * + */ + int IsCoreLimitNeedClose(bool& bClose); + + //重置内部的运行时数据 + void resetRunTimeData(); + +private: + + //字段分为两类,运行时数据和配置数据 + bool _closeCore; //屏蔽core开关, 运行时 + int _curExcStopCount; //当前服务异常停止个数, 运行时 + int _maxExcStopCount; //最大服务异常停止个数,配置 + time_t _excStopRecordTime; //第一次异常停止时间, 运行时 + int32_t _coreLimitTimeInterval; //时间间隔内core的限制,单位是分钟,配置 + time_t _enableCoreLimitTime; //上一次关闭core的时间, 运行时 + int32_t _coreLimitExpiredTime; //core关闭的持续时间,单位为分钟,配置 + + string _appName; //应用名 + string _serverName; //服务名 +}; + +typedef TC_AutoPtr ServerLimitResourcePtr; + +#endif + + diff --git a/NodeServer/ServerObject.cpp b/NodeServer/ServerObject.cpp new file mode 100644 index 00000000..7cb8bcb9 --- /dev/null +++ b/NodeServer/ServerObject.cpp @@ -0,0 +1,811 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "ServerObject.h" +#include "RegistryProxy.h" +#include "util/tc_clientsocket.h" +#include "servant/Communicator.h" +#include "NodeServer.h" +#include "CommandStart.h" +#include "CommandNotify.h" +#include "CommandStop.h" +#include "CommandDestroy.h" +#include "CommandAddFile.h" +#include "NodeRollLogger.h" + +ServerObject::ServerObject( const ServerDescriptor& tDesc) +: _tarsServer(true) +, _loaded(false) +, _patched(true) +, _noticed(false) +, _noticeFailTimes(0) +, _enSynState(true) +, _pid(0) +, _state(ServerObject::Inactive) +, _limitStateUpdated(false) +, _started(false) +{ + //60秒内最多启动10次,达到10次启动仍失败后,每隔600秒再重试一次 + _activatorPtr = new Activator(60,10,600); + + //服务相关修改集中放到setServerDescriptor函数中 + setServerDescriptor(tDesc); + + _serviceLimitResource = new ServerLimitResource(5,10,60,_application,_serverName); +} + +void ServerObject::setServerDescriptor( const ServerDescriptor& tDesc ) +{ + TLOGDEBUG("ServerObject::setServerDescriptor "<< tDesc.application << "." << tDesc.serverName <::const_iterator itAdapters; + for( itAdapters = _desc.adapters.begin(); itAdapters != _desc.adapters.end(); itAdapters++) + { + _adapterKeepAliveTime[itAdapters->first] = now; + } + _adapterKeepAliveTime["AdminAdapter"] = now; + setLastKeepAliveTime(now); +} + +bool ServerObject::isAutoStart() +{ + Lock lock(*this); + TLOGDEBUG( "ServerObject::isAutoStart "<< _application << "." << _serverName <<"|"<<_enabled<<"|"<<_loaded<<"|"<<_patched<<"|"<debug()<isActivatingLimited()) + { + if(_activatorPtr->isActivatingLimited()) + { + TLOGDEBUG("ServerObject::isAutoStart " << _application << "." << _serverName <<" not allow to restart in limited state"<getRegistryProxy()->updateServer( _nodeInfo.nodeName, _application, _serverName, tServerStateInfo); + } + else + { + AdminProxy::getInstance()->getRegistryProxy()->async_updateServer(NULL, _nodeInfo.nodeName, _application, _serverName, tServerStateInfo); + } + + //日志 + stringstream ss; + tServerStateInfo.displaySimple(ss); + NODE_LOG("synState")->debug()<getRegistryProxy()->async_updateServer( NULL, _nodeInfo.nodeName, _application, _serverName, tServerStateInfo); + + //日志 + stringstream ss; + tServerStateInfo.displaySimple(ss); + NODE_LOG("synState")->debug()<sendSignal(_pid, 0); + if (iRet == 0) + { + NODE_LOG("KeepAliveThread")->debug() <error() <::iterator it1 = _adapterKeepAliveTime.begin(); + if(adapter.empty()) + { + while (it1 != _adapterKeepAliveTime.end() ) + { + it1->second = t; + it1++; + } + return; + } + map::iterator it2 = _adapterKeepAliveTime.find(adapter); + if( it2 != _adapterKeepAliveTime.end()) + { + it2->second = t; + } + else + { + TLOGERROR("ServerObject::setLastKeepAliveTime "<::const_iterator it = _adapterKeepAliveTime.find(adapter); + if( it != _adapterKeepAliveTime.end()) + { + return it->second; + } + return -1; +} + + +bool ServerObject::isTimeOut(int iTimeout) +{ + Lock lock(*this); + time_t now = TNOW; + if(now - _keepAliveTime > iTimeout) + { + TLOGERROR("ServerObject::isTimeOut server time out "<|"<::const_iterator it = _adapterKeepAliveTime.begin(); + while (it != _adapterKeepAliveTime.end() ) + { + if(now - it->second > iTimeout) + { + TLOGERROR("ServerObject::isTimeOut server "<< it->first<<" time out "<second<<"|>|"<= 100)//默认为100ms,_timeout + { + NODE_LOG("KeepAliveThread")->debug()<|"<<100<debug()<<"server start time out "<getRegistryProxy()->async_reportVersion(NULL,_application, _serverName, _nodeInfo.nodeName, version); + + }catch(...) + { + _noticed = false; + } +} + +void ServerObject::setPid(pid_t pid) +{ + Lock lock(*this); + if (pid == _pid) + { + return; + } + NODE_LOG("startServer")->debug()<99?99:iPercent; + _patchInfo.iModifyTime = TNOW; +} + +void ServerObject::setPatchResult(const string &sPatchResult,const bool bSucc) +{ + Lock lock(*this); + _patchInfo.sResult = sPatchResult; + _patchInfo.bSucc = bSucc; +} + +void ServerObject::setPatchVersion(const string &sVersion) +{ + Lock lock(*this); + _patchInfo.sVersion = sVersion; +} + +string ServerObject::getPatchVersion() +{ + Lock lock(*this); + return _patchInfo.sVersion; +} + +int ServerObject::getPatchPercent(PatchInfo &tPatchInfo) +{ + TLOGDEBUG("ServerObject::getPatchPercent"<< _application << "_" << _serverName << "|"<< _serverId<< endl); + Lock lock(*this); + TLOGDEBUG("ServerObject::getPatchPercent "<< _application << "_" << _serverName << "|"<< _serverId << "get lock" << endl); + + tPatchInfo = _patchInfo; + //是否正在发布 + tPatchInfo.bPatching = (_state == ServerObject::Patching ||_state==ServerObject::BatchPatching)?true:false; + + if (tPatchInfo.bSucc == true || _state == ServerObject::Patching || _state == ServerObject::BatchPatching) + { + TLOGDEBUG("ServerObject::getPatchPercent "<< _desc.application + << "|" << _desc.serverName << "|succ:" << (tPatchInfo.bSucc?"true":"false") << "|" << toStringState(_state) << "|" << _patchInfo.iPercent << "%|" << _patchInfo.sResult << endl); + return 0; + } + + TLOGERROR("ServerObject::getPatchPercent "<< _desc.application + << "|" << _desc.serverName << "|succ:" << (tPatchInfo.bSucc?"true":"false") << "|" << toStringState(_state) << "|" << _patchInfo.iPercent << "%|" << _patchInfo.sResult << endl); + return -1; +} + +string ServerObject::decodeMacro(const string& value) const +{ + string tmp = value; + map::const_iterator it = _macro.begin(); + while(it != _macro.end()) + { + tmp = TC_Common::replace(tmp, "${" + it->first + "}", it->second); + ++it; + } + return tmp; +} + +void ServerObject::setMacro(const map& mMacro) +{ + Lock lock(*this); + map::const_iterator it1 = mMacro.begin(); + for(;it1!= mMacro.end();++it1) + { + map::iterator it2 = _macro.find(it1->first); + + if(it2 != _macro.end()) + { + it2->second = it1->second; + } + else + { + _macro[it1->first] = it1->second; + } + } +} + +void ServerObject::setScript(const string &sStartScript,const string &sStopScript,const string &sMonitorScript ) +{ + + _startScript = TC_File::simplifyDirectory(TC_Common::trim(sStartScript)); + _stopScript = TC_File::simplifyDirectory(TC_Common::trim(sStopScript)); + _monitorScript = TC_File::simplifyDirectory(TC_Common::trim(sMonitorScript)); +} + +bool ServerObject::getRemoteScript(const string &sFileName) +{ + string sFile = TC_File::simplifyDirectory(TC_Common::trim(sFileName)); + if(!sFile.empty()) + { + CommandAddFile commands(this,sFile); + commands.doProcess(); //拉取脚本 + return true; + } + return false; +} + +void ServerObject::doMonScript() +{ + try + { + string sResult; + time_t tNow = TNOW; + if(TC_File::isAbsolute(_monitorScript) == true) //监控脚本 + { + if(_state == ServerObject::Activating||tNow - _keepAliveTime > ServantHandle::HEART_BEAT_INTERVAL) + { + map mResult; + _activatorPtr->doScript(_serverId,_monitorScript,sResult,mResult); + if(mResult.find("pid") != mResult.end() && TC_Common::isdigit(mResult["pid"]) == true) + { + TLOGDEBUG("ServerObject::doMonScript "<< _serverId << "|"<< mResult["pid"] << endl); + keepAlive(TC_Common::strto(mResult["pid"])); + } + } + } + } + catch (exception &e) + { + TLOGERROR("ServerObject::doMonScript error:" << e.what() << endl); + } +} + +void ServerObject::checkServer(int iTimeout)//checkServer时对服务所占用的内存上报到主控 +{ + try + { + string sResult; + NODE_LOG("KeepAliveThread")->debug() <debug()<debug()<debug()<debug()<debug() < 0?_timeout:iTimeout; + if( _state != ServerObject::Inactive && isTimeOut(iRealTimeout)) + { + sResult = "[alarm] zombie process,no keep alive msg for " + TC_Common::tostr(iRealTimeout) + " seconds"; + NODE_LOG("KeepAliveThread")->debug()<debug() <debug() <addExcStopRecord(); + } + } + } + catch(exception &ex) + { + NODE_LOG("KeepAliveThread")->error()<error()<debug()<>改成上报物理内存 + vector vtStatm = TC_Common::sepstr(stream, " "); + if (vtStatm.size() < 2) + { + NODE_LOG("ReportMemThread")->error() <(stream) * 4); + NODE_LOG("ReportMemThread")->debug()<(stream)*4<<")OK."<error()<error()<error() << FILE_FUN << " ex:" << ex.what() << endl; + TLOGERROR(FILE_FUN << " ex:" << ex.what() << endl); + } + catch(...) + { + NODE_LOG("ReportMemThread")->error() << FILE_FUN << " unknown error" << endl; + TLOGERROR(FILE_FUN << "unknown ex." << endl); + } +} + +void ServerObject::checkCoredumpLimit() +{ + if(_state != ServerObject::Active || !_limitStateInfo.bEnableCoreLimit) + { + TLOGINFO(FILE_FUN<<"checkCoredumpLimit:server is inactive or disable corelimit"<IsCoreLimitNeedClose(bNeedClose); + + bool bNeedUpdate = (iRet==2)?true:false; + + if(_limitStateUpdated && bNeedClose) + { + _limitStateUpdated = setServerCoreLimit(true)?false:true;//设置成功后再屏蔽更新 + _limitStateInfo.bCloseCore = bNeedClose; + } + else if(bNeedUpdate && !bNeedClose) + { + setServerCoreLimit(false); + _limitStateInfo.bCloseCore = bNeedClose; + } + } + else + { + if(_limitStateUpdated) + { + _limitStateUpdated = setServerCoreLimit(_limitStateInfo.bCloseCore)?false:true; //设置成功后再屏蔽更新 + } + } +} + +bool ServerObject::setServerCoreLimit(bool bCloseCore) +{ + string sResult = "succ"; + const string sCmd = (bCloseCore)?("tars.closecore yes"):("tars.closecore no"); + + CommandNotify command(this,sCmd); + int iRet = command.doProcess(sResult); + + NODE_LOG("KeepAliveThread")->debug()<debug() << FILE_FUN << _serverId << "|" << _limitStateInfo.str() << endl; + + _serviceLimitResource->setLimitCheckInfo(tInfo.iMaxExcStopCount,tInfo.iCoreLimitTimeInterval,tInfo.iCoreLimitExpiredTime); + + _activatorPtr->setLimitInfo(tInfo.iActivatorTimeInterval, tInfo.iActivatorMaxCount, tInfo.iActivatorPunishInterval); + + _limitStateUpdated = true; +} + +//重置core计数信息 +void ServerObject::resetCoreInfo() +{ + _serviceLimitResource->resetRunTimeData(); +} + +void ServerObject::setStarted(bool bStarted) +{ + Lock lock(*this); + _started=bStarted; +} + +void ServerObject::setStartTime(int64_t iStartTime) +{ + Lock lock(*this); + _startTime = iStartTime; +} \ No newline at end of file diff --git a/NodeServer/ServerObject.h b/NodeServer/ServerObject.h new file mode 100644 index 00000000..9006c897 --- /dev/null +++ b/NodeServer/ServerObject.h @@ -0,0 +1,526 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __SERVER_OBJECT_H_ +#define __SERVER_OBJECT_H_ + +#include "Node.h" +#include "Registry.h" +#include +#include "Activator.h" +#include "util/tc_file.h" +#include "util/tc_config.h" +#include "servant/AdminF.h" +#include "servant/NodeF.h" +#include "servant/TarsLogger.h" +#include "PlatformInfo.h" +#include "PropertyReporter.h" +#include "ServerLimitResource.h" + +using namespace tars; +using namespace std; + +class ServerObject : public TC_ThreadRecLock, public TC_HandleBase +{ +public: + enum InternalServerState + { + Inactive, + Activating, + Active, + Deactivating, + Destroying, + Destroyed, + Loading, + Patching, + BatchPatching, + AddFilesing, + }; + + enum EM_CoreType + { + EM_AUTO_LIMIT, + EM_MANUAL_LIMIT + }; + + /** + *@brief 服务进程的limit资源状态,比如core属性资源 + * + *服务的corelimit初始状态默认为EM_AUTO_LIMIT+false + */ + struct ServerLimitInfo + { + bool bEnableCoreLimit; //资源属性开关 + bool bCloseCore; //core属性的状态,屏蔽:true,打开:false + EM_CoreType eCoreType; //服务core的当前屏蔽方式 + int iMaxExcStopCount; //最大服务异常停止个数 + int32_t iCoreLimitTimeInterval; //时间间隔内core的限制,单位是分钟 + int32_t iCoreLimitExpiredTime; //core关闭的持续时间,单位为分钟 + int32_t iMonitorIntervalMs; //keepalive监控时间间隔 + + int iActivatorMaxCount; //最大启动次数 + int iActivatorTimeInterval; //时间 + int iActivatorPunishInterval; //惩罚受限时间间隔 + bool bReportLoadInfo; //是否上报节点负载信息,默认上报 + + ServerLimitInfo() + : bEnableCoreLimit(false) + , bCloseCore(false) + , eCoreType(EM_AUTO_LIMIT) + , iMaxExcStopCount(3) + , iCoreLimitTimeInterval(5) + , iCoreLimitExpiredTime(30) + , iMonitorIntervalMs(1000) + , iActivatorMaxCount(10) + , iActivatorTimeInterval(60) + , iActivatorPunishInterval(600) + , bReportLoadInfo(true) + { + } + + ostream& displaySimple(ostream& _os, int _level=0) const + { + tars::TarsDisplayer _ds(_os, _level); + _ds.displaySimple(bEnableCoreLimit, true); + _ds.displaySimple(bCloseCore, true); + _ds.displaySimple(eCoreType, true); + _ds.displaySimple(iMaxExcStopCount, true); + _ds.displaySimple(iCoreLimitTimeInterval, true); + _ds.displaySimple(iCoreLimitExpiredTime, true); + _ds.displaySimple(iMonitorIntervalMs, true); + + _ds.displaySimple(iActivatorMaxCount, true); + _ds.displaySimple(iActivatorTimeInterval, true); + _ds.displaySimple(iActivatorPunishInterval, false); + + _ds.displaySimple(bReportLoadInfo, true); + return _os; + } + + string str() + { + stringstream ss; + displaySimple(ss); + return ss.str(); + } + }; + +public: + + /** + * 构造函数 + * @param tDesc server描述结构 + */ + ServerObject( const ServerDescriptor& tDesc); + + /** + * 析够 + */ + ~ServerObject() { }; + + /** + * 是否是tars服务 + * + * @return bool + */ + bool isTarsServer() {return _tarsServer;} + + /** + * 是否是enable + * + * @return bool + */ + bool isEnabled() {return _enabled;} + + /** + * 服务是否自动启动 + *,用来防止问题服务不断重启影响其它服务 + * @return bool + */ + bool isAutoStart() ; + + /** + * 设置服务enable + * @param enable + */ + void setEnabled(bool enable){_enabled = enable; } + + /** + * 设置服务已patch + * @param enable + */ + void setPatched(bool bPatched) + { + _patched = bPatched; + _patchInfo.iPercent = 100; + } + + /** + *设置服务已load + * @param enable + */ + void setLoaded(bool bLoaded){_loaded = bLoaded;} + + /** + *是否允许同步服务的状态到主控中心,在某些情况下,服务发布了,但是还不想对外提供服务 + *则可以设置这个值 + *@param bEn + */ + void setEnSynState(bool bEn) { _enSynState = bEn;} + + bool IsEnSynState(){ return _enSynState;} + +public: + + /** + * 验证server对应pid是否存在 + * @return int + */ + int checkPid(); + + /** + * 设置server对应pid + */ + void setPid( pid_t pid ); + + /** + * 获取server对应pid + */ + + int getPid() { return _pid; } + + /** + * 获取server对应本地socket + */ + + TC_Endpoint getLocalEndpoint() { return _localEndpoint; } + + /** + * 设置server对应本地socket + */ + + void setLocalEndpoint(const TC_Endpoint &tLocalEndpoint) { _localEndpoint = tLocalEndpoint; } + + /** + * 获取server上报信息 + * @para string obj + * @para pid_t pid上报pid + * @return void + */ + void keepAlive( pid_t pid, const string &adapter=""); + + /** + * 取的server最近keepAlive时间 + * @return int + */ + int getLastKeepAliveTime(const string &adapter=""); + + /** + * 设置server最近keepAlive时间 + * @return void + */ + void setLastKeepAliveTime(int t,const string &adapter=""); + + /** + * 服务是否已timeout + * @param iTimeout + * @return bool + */ + bool isTimeOut(int iTimeout); + + /* + * 是否已经通过commandStart启动成功 + */ + bool isStarted() {return _started;} + +public: + + /** + * 跟registry同步server当前状态 + * @return void + */ + void synState(); + + /** + * 异步跟registry同步server当前状态 + * @return void + */ + void asyncSynState(); + + /** + * 设置server当前状态 + * @param eState + * @param bSynState 是否同步server状态到registry + * @return void + */ + void setState( InternalServerState eState, bool bSynState=true); + + /** + *设置server上一次状态,当server状态发生变化时调用 + */ + void setLastState(InternalServerState eState); + + /** + * 获取服务状态 + * + * @return tars::ServerState + */ + tars::ServerState getState(); + + /** + * 获取server内部状态 + * @return void + */ + InternalServerState getInternalState() { return _state; } + + /** + *获取server上一次内部状态 + *@return InternalServerState + */ + InternalServerState getLastState() {return _lastState;} + + /** + *转换指定server内部状态为字符串形式 + * @para eState + * @return string + */ + string toStringState( InternalServerState eState ) const; + + /** + *转换指定server内部状态为one::ServerState形式 consider + * @para eState + * @return ServerState + */ + ServerState toServerState( InternalServerState eState ) const; + + /** + *监控server状态 + * @para iTimeout 心跳超时时间 + * @return void + */ + void checkServer(int iTimeout); + + /** + * 属性上报单独出来 + */ + void reportMemProperty(); + + /** + *设置脚本文件 + * @para tConf 脚本文件 + * @return void + */ + string decodeMacro(const string& value) const ; + +public: + + /** + *是否为脚本文件 + * @para sFileName 文件名 + * @return bool + */ + bool isScriptFile(const string &sFileName); + + /** + * 拉取脚本文件 + * @para sFileName 文件名 + * @return bool + */ + bool getRemoteScript(const string &sFileName); + + /** + *执行监控脚本文件 + * @para sFileName 文件名 + * @return void + */ + void doMonScript(); + +public: + /** + *s设置下载百分比 + * @para iPercent 文件已下载百分比 + * @return bool + */ + void setPatchPercent(const int iPercent); + + /** + *s设置下载结果 + * @para sPatchResult + * @return bool + */ + void setPatchResult(const string &sPatchResult,const bool bSucc = false); + + /** + *s设置下载版本 + * @para sPatchResult + * @return bool + */ + void setPatchVersion(const string &sVersion); + + /** + * 获取正在下载的版本号 + * @return string + */ + string getPatchVersion(); + + /** + * 获取下载信息 + * @para tPatchInfo + * @return int + */ + int getPatchPercent(PatchInfo &tPatchInfo); + +public: + ServerDescriptor getServerDescriptor() { return _desc; } + ActivatorPtr getActivator() { return _activatorPtr; } + string getExePath(){return _exePath;} + string getExeFile(){return _exeFile;} + string getConfigFile(){return _confFile;} + string getLogPath(){return _logPath;} + string getLibPath(){return _libPath;} + string getServerDir(){return _serverDir;} + string getServerId(){return _serverId;} + string getServerType(){return _serverType;} + string getStartScript() {return _startScript;} + string getStopScript() {return _stopScript;} + string getMonitorScript() {return _monitorScript;} + string getEnv() { return _env; } + string getRedirectPath() {return _redirectPath;} + + //java服务 + string getJvmParams() {return _jvmParams;} + string getMainClass() {return _mainClass;} + string getClassPath() {return _classPath;} + string getBackupFileNames(){return _backupFiles;} + + void setServerDescriptor( const ServerDescriptor& tDesc ); + void setVersion( const string &version ); + void setExeFile(const string &sExeFile){_exeFile = sExeFile;} + void setExePath(const string &sExePath){_exePath = sExePath;} + void setConfigFile(const string &sConfFile){_confFile = sConfFile;} + void setLogPath(const string &sLogPath){_logPath = sLogPath;} + void setLibPath(const string &sLibPath){_libPath = sLibPath;} + void setServerDir(const string &sServerDir){_serverDir = sServerDir;} + void setNodeInfo(const NodeInfo &tNodeInfo){_nodeInfo = tNodeInfo;} + void setServerType( const string &sType ){ _serverType = TC_Common::lower(TC_Common::trim(sType));_serverType == "not_tars"?_tarsServer = false:_tarsServer=true;} + void setMacro(const map& mMacro); + void setScript(const string &sStartScript,const string &sStopScript,const string &sMonitorScript); + + void setEnv(const string & sEnv) { _env = sEnv; } + void setHeartTimeout(int iTimeout) { _timeout = iTimeout; } + + //java服务 + void setJvmParams(const string &sJvmParams){_jvmParams = sJvmParams;} + void setMainClass(const string &sMainClass){_mainClass = TC_Common::trim(sMainClass);} + void setClassPath(const string &sClassPath){_classPath = sClassPath;} + void setRedirectPath(const string& sRedirectpath) {_redirectPath = sRedirectpath;} + void setBackupFileNames(const string& sFileNames){_backupFiles = sFileNames;} + + //重置core计数信息 + void resetCoreInfo(); + + //是否已经通过commandStart启动成功 + void setStarted(bool bStarted); + + //设置启动的时间,作为checkpid系统延迟判断的起点 + void setStartTime(int64_t iStartTime); + + //判断是否启动超时 + bool isStartTimeOut(); +public: + /** + * auto check routine + */ + void checkCoredumpLimit(); + + /** + * server restart and set limitupdate state + */ + void setLimitInfoUpdate(bool bUpdate); + + void setServerLimitInfo(const ServerLimitInfo& tInfo); + + bool setServerCoreLimit(bool bCloseCore); + +private: + bool _tarsServer; //是否tars服务 + string _serverType; //服务类型 tars_cpp tars_java not_tars + +private: + bool _enabled; //服务是否有效 + bool _loaded; //服务配置是否已成功加载 + bool _patched; //服务可执行程序是否已成功下载 + bool _noticed; //服务当前状态是否已通知registry。 + unsigned _noticeFailTimes; //同步服务状态到registry连续失败次数 + bool _enSynState; //是否允许同步服务的状态到主控 + +private: + string _application; //服务所属app + string _serverName; //服务名称 + string _serverId; //服务id为App.ServerName.Ip形式 + +private: + string _jvmParams; //java服务jvm + string _mainClass; //java服务main class + string _classPath; //java服务 class path + string _redirectPath; //标准输出和错误输出重定向目录 + +private: + string _startScript; //启动脚本 + string _stopScript; //停止脚本 + string _monitorScript; //监控脚本 + +private: + string _serverDir; //服务数据目录 + string _confFile; //服务配置文件目录 + string _exePath; //一般为_serverDir+"/bin" 可个性指定 + string _exeFile; //一般为_exePath+_serverName 可个性指定 + string _logPath; //服务日志目录 + string _libPath; //动态库目录 一般为_desc.basePath/lib + map _macro; //服务宏 + +private: + PatchInfo _patchInfo; //下载信息 + +private: + pid_t _pid; //服务进程号 + string _version; //TARS版本 + NodeInfo _nodeInfo; //服务所在node信息 + TC_Endpoint _localEndpoint; //本地socket + ServerDescriptor _desc; //服务描述,主要用于生成配置文件等 + ActivatorPtr _activatorPtr; //用于启动、停止服务 + time_t _keepAliveTime; //服务最近上报时间 + map _adapterKeepAliveTime; //各adapter最近上报时间,用来判断adapter是否上报超时 + + InternalServerState _state; //当前服务状态 + InternalServerState _lastState; //上一次服务状态 + + int _timeout; //心跳超时时间 + string _env; //环境变量字符串 + string _backupFiles; //针对java服务发布时bin目录下需要保留的文件;可以用;|来分隔 + +private: + bool _limitStateUpdated; //服务的limit配置是否有更新,重启也算更新 + ServerLimitInfo _limitStateInfo; //通过node配置设置的资源信息 + ServerLimitResourcePtr _serviceLimitResource; + bool _started; //是否已经通过commandStart启动成功 + int64_t _startTime; //启动的时间,作为checkpid系统延迟判断的起点 +}; + +typedef TC_AutoPtr ServerObjectPtr; + +#endif + diff --git a/NodeServer/SingleFileDownloader.cpp b/NodeServer/SingleFileDownloader.cpp new file mode 100644 index 00000000..f2899cfa --- /dev/null +++ b/NodeServer/SingleFileDownloader.cpp @@ -0,0 +1,128 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "SingleFileDownloader.h" +#include "servant/TarsLogger.h" +#include "util.h" + +DownloadTaskFactory* DownloadTaskFactory::_instance = new DownloadTaskFactory(); + +int SingleFileDownloader::download(const PatchPrx &patchPrx, const string &remoteFile, const string &localFile, const DownloadEventPtr &pPtr, std::string & sResult) +{ + + vector vFiles; + int ret = 0; + + for( int i = 0; i < 2; i ++) + { + try + { + ret = patchPrx->listFileInfo(remoteFile, vFiles); + break; + } + catch(TarsException& ex) + { + TLOGERROR("SingleFileDownloader::download " << (remoteFile + " TarsException " + ex.what())<< endl); + } + } + + //1表示是文件 + if(ret != 1) + { + sResult = remoteFile + " is not an file"; + return -1; + } + + if(vFiles.size() < 1) + { + sResult = remoteFile + " not exist"; + return -2; + } + + tars::FileInfo fileInfo = vFiles[0]; + + FILE *fp = fopen(localFile.c_str(), "wb"); + if (!fp) + { + sResult = localFile + " can not write"; + return -3; + } + + //循环下载文件到本地 + vector buffer; + int pos = 0; + int downloadRet = 0; + bool fileEnded = false; + while (true) + { + buffer.clear(); + + //最多尝试两次 + for( int i = 0; i < 2; i ++) + { + try + { + downloadRet = patchPrx->download(remoteFile, pos, buffer); + break; + } + catch(TarsException& ex) + { + TLOGERROR("SingleFileDownloader::download "<< (remoteFile + " TarsException " + ex.what()) << endl); + } + } + + if (downloadRet < 0) + { + TLOGERROR("SingleFileDownloader::download " << "|downloadRet:" << downloadRet << "|remoteFile:" << remoteFile << endl); + sResult = remoteFile + " download from tarspatch error " + TC_Common::tostr(downloadRet); + ret = downloadRet - 100; + break; + } + else if (downloadRet == 0) + { + size_t r = fwrite((void*)&buffer[0], 1, buffer.size(), fp); + if (r == 0) + { + TLOGERROR("SingleFileDownloader::download fwrite file '" + localFile + "' error!" << endl); + sResult = "fwrite file '" + localFile + "' error!"; + ret = -5; + break; + } + pos += r; + if(pPtr) + { + pPtr->onDownloading(fileInfo, pos); + } + } + else if (downloadRet == 1) + { + TLOGDEBUG("SingleFileDownloader::download load succ " << remoteFile << "|pos:"< +#include "util/tc_monitor.h" +#include "util/tc_hash_fun.h" + +class DownloadEvent : public TC_HandleBase +{ +public: + virtual void onDownloading(const FileInfo &fi, int pos) = 0; +}; + +typedef TC_AutoPtr DownloadEventPtr; + + +//下载任务 +struct DownloadTask +{ + string sLocalTgzFile; +}; + +inline bool operator<(const DownloadTask&l, const DownloadTask&r) +{ + if(l.sLocalTgzFile != r.sLocalTgzFile) + { + return (l.sLocalTgzFile < r.sLocalTgzFile); + } + + return false; +} + +#define POOLSIZE 10 + +class DownloadTaskFactory +{ + /**定义hash处理器*/ + using hash_functor = std::function; + +public: + + tars::TC_ThreadRecLock* getRecLock(const DownloadTask& task) + { + size_t hashcode = _hashf(task.sLocalTgzFile); + size_t index = hashcode % POOLSIZE; + return &_lockPool[index]; + } + + static DownloadTaskFactory& getInstance() + { + return *_instance; + } + +private: + DownloadTaskFactory() + : _hashf(tars::hash()) + { + } + +private: + tars::TC_ThreadRecLock _lockPool[POOLSIZE]; + hash_functor _hashf; + static DownloadTaskFactory* _instance; +}; + +//从patch上下载单个文件 +class SingleFileDownloader +{ +public: + static int download(const PatchPrx &patchPrx, const string &remoteFile, const string &localFile, const DownloadEventPtr &pPtr, std::string & sResult); + +private: +}; +////////////////////////////////////////////////////////////// +#endif + diff --git a/NodeServer/main.cpp b/NodeServer/main.cpp new file mode 100644 index 00000000..21e9a097 --- /dev/null +++ b/NodeServer/main.cpp @@ -0,0 +1,253 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "NodeServer.h" +#include "servant/Communicator.h" +#include "util/tc_option.h" +#include "util/tc_file.h" +#include "util/tc_config.h" +#include + +using namespace std; +using namespace tars; + +NodeServer g_app; +TC_Config* g_pconf; + +static string outfill(const string& s, char c = ' ', int n = 29) +{ + return (s + string(abs(n - (int)s.length()), c)); +} + +bool getConfig(const string &sLocator,const string &sRegistryObj,string &sNodeId,string &sLocalIp, string &sConfigFile, bool bCloseCout) +{ + try + { + //string sLocalIp; + string sResult; + string sTemplate; + TC_Config tConf; + CommunicatorFactory::getInstance()->getCommunicator()->setProperty("locator",sLocator); + RegistryPrx pRegistryPrx = CommunicatorFactory::getInstance()->getCommunicator()->stringToProxy(sRegistryObj); + if( sLocalIp.empty() && pRegistryPrx->getClientIp(sLocalIp) != 0) + { + cerr<<"cannot get localip: " <getNodeTemplate(sNodeId,sTemplate); + if(TC_Common::trim(sTemplate) == "" ) + { + cerr << "cannot get node Template nodeid:"<"); + if (sCloseCoutValue == "1") + { + sTemplate = TC_Common::replace(sTemplate, "closecout=1", "closecout=0"); + tConf.parseString(sTemplate); + } + else if (sCloseCoutValue.empty()) + { + map m; + m["closecout"] = "0"; + tConf.insertDomainParam("/tars/application/server", m,true); + } + else + { + cerr << "failed to set closeout value" << endl; + } + } + + string sConfigPath = TC_File::extractFilePath(sConfigFile); + if(!TC_File::makeDirRecursive( sConfigPath )) + { + cerr<<"cannot create dir: " <"]; + + ServantPrx prx = CommunicatorFactory::getInstance()->getCommunicator()->stringToProxy(nodeObj); + prx->tars_ping(); +} + +void parseConfig(int argc, char *argv[]) +{ + + TC_Option tOp;//consider + tOp.decode(argc, argv); + + if (tOp.hasParam("nodeversion")) + { + cout << "Node:" << TARS_VERSION << "_" << NODE_VERSION << endl; + exit(0); + } + + if (tOp.hasParam("monitor")) + { + try + { + string configFile = tOp.getValue("config"); + + monitorNode(configFile); + } + catch (exception &ex) + { + cout << "failed:" << ex.what() << endl; + exit(-1); + } + exit(0); + return; + } + + string sLocator = tOp.getValue("locator"); + string sNodeId = tOp.getValue("nodeid"); + string sConfigFile = tOp.getValue("config"); + string sRegistryObj = tOp.getValue("registryObj"); + string sLocalIp = tOp.getValue("localip"); + + if(sConfigFile == "") + { + cerr << endl; + cerr <<"start server with locator config, for example: "< mOp = tOp.getMulti(); + for(map::const_iterator it = mOp.begin(); it != mOp.end(); ++it) + { + cout << outfill( it->first)<< it->second << endl; + } + +} + +int main( int argc, char* argv[] ) +{ + try + { + bool bNoDaemon = false; + for (int i = 1; i < argc; ++i) + { + if (::strcmp(argv[i], "--monitor") == 0) + { + bNoDaemon = true; + break; + } + } + + if (!bNoDaemon) + { + TC_Common::daemon(); + } + + parseConfig(argc,argv); + + g_pconf = &g_app.getConfig(); + + g_app.main( argc, argv ); + g_app.waitForShutdown(); + } + catch ( exception& ex ) + { + cout<< ex.what() << endl; + } + catch ( ... ) + { + cout<< "main unknow exception cathed" << endl; + } + + return 0; +} diff --git a/NodeServer/util.h b/NodeServer/util.h new file mode 100644 index 00000000..bf6b93d2 --- /dev/null +++ b/NodeServer/util.h @@ -0,0 +1,27 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef _UTIL_H +#define _UTIL_H + +#include "util/tc_common.h" + +#define __FILENAME__ (strrchr(__FILE__, '/') ? (strrchr(__FILE__, '/') + 1):__FILE__) + +#define FILE_FUN __FILENAME__<<":"<<__FUNCTION__<<":"<<__LINE__<<"|" +#define FILE_FUN_STR TC_Common::tostr(__FILENAME__)+":"+TC_Common::tostr(__FUNCTION__)+":"+TC_Common::tostr(__LINE__)+"|" + +#endif diff --git a/NotifyServer/CMakeLists.txt b/NotifyServer/CMakeLists.txt new file mode 100644 index 00000000..9fd0c566 --- /dev/null +++ b/NotifyServer/CMakeLists.txt @@ -0,0 +1,6 @@ + +set(MODULE "tarsnotify") + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/deploy/${MODULE}/) + +complice_module(${MODULE}) diff --git a/NotifyServer/LoadDbThread.cpp b/NotifyServer/LoadDbThread.cpp new file mode 100644 index 00000000..0ed9c667 --- /dev/null +++ b/NotifyServer/LoadDbThread.cpp @@ -0,0 +1,129 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "LoadDbThread.h" +#include "NotifyServer.h" + +LoadDbThread::LoadDbThread() +: _interval(30) +, _terminate(false) +{ + +} + +LoadDbThread::~LoadDbThread() +{ + if(isAlive()) + { + terminate(); + getThreadControl().join(); + } +} + +void LoadDbThread::terminate() +{ + _terminate = true; + + TC_ThreadLock::Lock lock(*this); + + notifyAll(); +} + +void LoadDbThread::init() +{ + try + { + map mDbConf = g_pconf->getDomainMap("/tars/db"); + assert(!mDbConf.empty()); + + TC_DBConf tcDBConf; + tcDBConf.loadFromMap(mDbConf); + + _mysql.init(tcDBConf); + + TLOGDEBUG("LoadDbThread::init init mysql conf succ." << endl); + } + catch(exception &ex) + { + TLOGERROR("LoadDbThread::init ex:" << ex.what() << endl); + FDLOG("EX") << "LoadDbThread::init ex:" << ex.what() << endl; + } +} + +void LoadDbThread::run() +{ + size_t iLastTime = 0; + size_t iNow = TNOW; + + while (!_terminate) + { + if(iNow - iLastTime >= _interval) + { + loadData(); + + iLastTime = iNow; + } + + { + TC_ThreadLock::Lock lock(*this); + timedWait(1000); + } + } +} + +void LoadDbThread::loadData() +{ + try + { + TC_Mysql::MysqlData mysqlData; + map &mTmep = _data.getWriter(); + mTmep.clear(); + size_t iOffset(0); + + do + { + string sSql("select application, set_name, set_area, set_group, server_name, node_name from t_server_conf limit 1000 offset "); + sSql = sSql + TC_Common::tostr(iOffset) +";"; + + mysqlData = _mysql.queryRecord(sSql); + + for (size_t i = 0; i < mysqlData.size(); i++) + { + string sValue = mysqlData[i]["set_name"] +"."+ mysqlData[i]["set_area"]+ "." + mysqlData[i]["set_group"]; + if (mysqlData[i]["set_name"].empty()) + { + continue; + } + + string sKey = mysqlData[i]["application"] + "." + mysqlData[i]["server_name"] + mysqlData[i]["node_name"]; + mTmep.insert(map::value_type(sKey, sValue)); + } + + iOffset += mysqlData.size(); + + } while (iOffset % 1000 == 0); + + _data.swap(); + + TLOGDEBUG("LoadDbThread::loadData load data finish, _mSetApp size:" << mTmep.size() << endl); + + } + catch (exception &ex) + { + TLOGERROR("LoadDbThread::loadData exception:" << ex.what() << endl); + FDLOG("EX") << "LoadDbThread::loadData exception:" << ex.what() << endl; + } +} diff --git a/NotifyServer/LoadDbThread.h b/NotifyServer/LoadDbThread.h new file mode 100644 index 00000000..43db14cd --- /dev/null +++ b/NotifyServer/LoadDbThread.h @@ -0,0 +1,152 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __LOAD_DB_THREAD_H_ +#define __LOAD_DB_THREAD_H_ + +#include "util/tc_thread.h" +#include "util/tc_monitor.h" +#include "util/tc_mysql.h" +#include "servant/TarsLogger.h" +//#include "NotifyServer.h" + +using namespace std; +using namespace tars; + +/** + * ˫buff + */ +template +class DataWrapper +{ +public: + DataWrapper() + :_swap(true) + { + } + + ~DataWrapper() + { + } + + T &getWriter() + { + if (_swap) + { + return _a; + } + else + { + return _b; + } + } + + T &getReader() + { + if (_swap) + { + return _b; + } + else + { + return _a; + } + } + + void swap() + { + _swap = !_swap; + } + +private: + bool _swap; + T _a; + T _b; +}; + +/** + * dbsetϢ߳ + */ +class LoadDbThread : public TC_Thread, public tars::TC_ThreadLock +{ +public: + typedef DataWrapper< map > Data; + + /** + * 캯 + */ + LoadDbThread(); + + /** + * + */ + ~LoadDbThread(); + + /** + * ʼ + */ + void init(); + + /** + * + */ + void run(); + + /** + * ֹͣ + */ + void terminate(); + + /** + * ȡsetϢ + */ + string getSetName(const string &sAppName) + { + map &mData = _data.getReader(); + map::iterator it = mData.find(sAppName); + + if (it != mData.end()) + { + return it->second; + } + + return ""; + + } + +private: + + /** + * db + */ + void loadData(); + +private: + //dbݵʱ + size_t _interval; + + //ֹͣ + bool _terminate; + + //ݿ + TC_Mysql _mysql; + + //˫buff + Data _data; +}; + + +#endif diff --git a/NotifyServer/NotifyImp.cpp b/NotifyServer/NotifyImp.cpp new file mode 100644 index 00000000..71bd0448 --- /dev/null +++ b/NotifyServer/NotifyImp.cpp @@ -0,0 +1,350 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "NotifyImp.h" +#include "jmem/jmem_hashmap.h" +#include "NotifyServer.h" + +extern TC_Config * g_pconf; +extern TarsHashMap * g_notifyHash; + +void NotifyImp::loadconf() +{ + TC_DBConf tcDBConf; + tcDBConf.loadFromMap(g_pconf->getDomainMap("/tars/db")); + + _mysqlConfig.init(tcDBConf); + + _sql = (*g_pconf)["/tars/"]; + _maxPageSize = TC_Common::strto((*g_pconf)["/tars/hash"]); + _maxPageNum = TC_Common::strto((*g_pconf)["/tars/hash"]); + + map m = g_pconf->getDomainMap("/tars/filter"); + for(map::iterator it= m.begin();it != m.end();it++) + { + vector vFilters = TC_Common::sepstr(it->second,";|"); + _setFilter[it->first].insert(vFilters.begin(),vFilters.end()); + } + +} + +void NotifyImp::initialize() +{ + loadconf(); +} + +bool NotifyImp::IsdbTableExist(const string& sTbName) +{ + try + { + TC_Mysql::MysqlData tTotalRecord = _mysqlConfig.queryRecord("show tables like '%"+sTbName+"%'"); + + TLOGINFO("NotifyImp::IsdbTableExist show tables like '%" + sTbName + "%|affected:" << tTotalRecord.size() << endl); + + if (tTotalRecord.size() > 0) + { + return true; + } + else + { + TLOGERROR("NotifyImp::IsdbTableExist sTbName:" << sTbName << "|doesn't exist" << endl); + return false; + } + + } + catch(TC_Mysql_Exception& ex) + { + TLOGERROR("NotifyImp::IsdbTableExist exception:" << ex.what() << endl); + return false; + } + catch(...) + { + TLOGERROR("NotifyImp::IsdbTableExist unknown exception." << endl); + return false; + } +} + +void NotifyImp::creatTb(const string &sTbName) +{ + try + { + if (!IsdbTableExist(sTbName)) + { + string sSql = TC_Common::replace(_sql, "${TABLE}",sTbName); + + _mysqlConfig.execute(sSql); + + TLOGDEBUG("NotifyImp::creatTb sSql:" << sSql << endl); + } + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("NotifyImp::creatTb exception:" << ex.what() << endl); + } + catch(...) + { + TLOGERROR("NotifyImp::IsdbTableExist unknown exception." << endl); + } +} + +bool NotifyImp::IsNeedFilte(const string& sServerName,const string& sResult) +{ + if(_setFilter.find(sServerName) != _setFilter.end()) + { + set& setFilter = _setFilter.find(sServerName)->second; + for(set::iterator it = setFilter.begin(); it != setFilter.end();it++) + { + if(sResult.find(*it) != string::npos) + { + return true; + } + } + } + + const string sDefault = "default"; + if(_setFilter.find(sDefault) != _setFilter.end()) + { + set& setFilter = _setFilter.find(sDefault)->second; + for(set::iterator it = setFilter.begin(); it != setFilter.end();it++) + { + if(sResult.find(*it) != string::npos) + { + return true; + } + } + } + + return false; +} + +void NotifyImp::reportServer(const string& sServerName, const string& sThreadId, const string& sResult, tars::TarsCurrentPtr current) +{ + TLOGDEBUG("NotifyImp::reportServer sServerName:" << sServerName << "|ip:" << current->getIp() << "|sThreadId:" << sThreadId << "|sResult:" << sResult << endl); + //DLOG << "NotifyImp::reportServer sServerName:" << sServerName << "|ip:" << current->getIp() << "|sThreadId:" << sThreadId << "|sResult:" << sResult << endl; + + if(IsNeedFilte(sServerName,sResult)) + { + TLOGWARN("NotifyImp::reportServer sServerName:" << sServerName << "|ip:" << current->getIp() << "|sThreadId:" << sThreadId << "|sResult:" << sResult <<"|filted"<< endl); + return; + } + + ReportInfo info; + info.sApp = sServerName; + info.sServer = sServerName; + + vector vModule = TC_Common::sepstr(sServerName,"."); + if(vModule.size() >= 2) + { + info.sApp = vModule[0]; + info.sServer = vModule[1]; + } + + info.eType = REPORT; + info.sSet = g_app.getLoadDbThread()->getSetName(sServerName + current->getIp()); + info.sMessage = sResult; + info.sThreadId = sThreadId; + + reportNotifyInfo(info, current); + + return; +} + +void NotifyImp::notifyServer(const string& sServerName, NOTIFYLEVEL level, const string& sMessage, tars::TarsCurrentPtr current) +{ + ReportInfo info; + info.sApp = sServerName; + info.sServer = sServerName; + + + vector vModule = TC_Common::sepstr(sServerName, "."); + if (vModule.size() >= 2) + { + info.sApp = vModule[0]; + info.sServer = vModule[1]; + } + + info.eType = NOTIFY; + info.sSet = g_app.getLoadDbThread()->getSetName(sServerName + current->getIp()); + info.sMessage = sMessage; + info.eLevel = level; + + reportNotifyInfo(info, current); + + return; +} + +int NotifyImp::getNotifyInfo(const tars::NotifyKey & stKey,tars::NotifyInfo &stInfo,tars::TarsCurrentPtr current) +{ + int iRet = g_notifyHash->get(stKey, stInfo); + + ostringstream os; + stKey.displaySimple(os); + os << "|"; + stInfo.displaySimple(os); + + TLOGDEBUG("NotifyImp::getNotifyInfo iRet:" << iRet << "|os:" << os.str() << endl); + + return iRet; +} + +void NotifyImp::reportNotifyInfo(const tars::ReportInfo & info, tars::TarsCurrentPtr current) +{ + switch (info.eType) + { + case (REPORT): + { + TLOGDEBUG("NotifyImp::reportNotifyInfo reportServer:" << info.sApp + "." + info.sServer << "|sSet:" << info.sSet << "|sContainer:" << info.sContainer << "|ip:" << current->getIp() + << "|sThreadId:" << info.sThreadId << "|sMessage:" << info.sMessage << endl); + + // DLOG << "NotifyImp::reportNotifyInfo reportServer:" << info.sApp + "." + info.sServer << "|sSet:" << info.sSet << "|sContainer:" << info.sContainer << "|ip:" << current->getIp() + // << "|sThreadId:" << info.sThreadId << "|sMessage:" << info.sMessage << endl; + + if (IsNeedFilte(info.sApp + info.sServer, info.sMessage)) + { + TLOGWARN("NotifyImp::reportNotifyInfo reportServer:" << info.sApp + "." + info.sServer << "|sSet:" << info.sSet << "|sContainer:" << info.sContainer << "|ip:" << current->getIp() + << "|sThreadId:" << info.sThreadId << "|sMessage:" << info.sMessage << "|filted" << endl); + + return; + } + + string sql; + TC_Mysql::RECORD_DATA rd; + + rd["application"] = make_pair(TC_Mysql::DB_STR, info.sApp); + rd["server_name"] = make_pair(TC_Mysql::DB_STR, info.sServer); + rd["container_name"] = make_pair(TC_Mysql::DB_STR, info.sContainer); + rd["server_id"] = make_pair(TC_Mysql::DB_STR, info.sApp +"."+ info.sServer + "_" + current->getIp()); + rd["node_name"] = make_pair(TC_Mysql::DB_STR, current->getIp()); + rd["thread_id"] = make_pair(TC_Mysql::DB_STR, info.sThreadId); + + if (!info.sSet.empty()) + { + vector v = TC_Common::sepstr(info.sSet, "."); + if (v.size() != 3 || (v.size() == 3 && (v[0] == "*" || v[1] == "*"))) + { + TLOGERROR("NotifyImp::reportNotifyInfo bad set name:" << info.sSet << endl); + } + else + { + rd["set_name"] = make_pair(TC_Mysql::DB_STR, v[0]); + rd["set_area"] = make_pair(TC_Mysql::DB_STR, v[1]); + rd["set_group"] = make_pair(TC_Mysql::DB_STR, v[2]); + } + + } + else + { + rd["set_name"] = make_pair(TC_Mysql::DB_STR, ""); + rd["set_area"] = make_pair(TC_Mysql::DB_STR, ""); + rd["set_group"] = make_pair(TC_Mysql::DB_STR, ""); + } + + rd["result"] = make_pair(TC_Mysql::DB_STR, info.sMessage); + rd["notifytime"] = make_pair(TC_Mysql::DB_INT, "now()"); + string sTable = "t_server_notifys"; + try + { + _mysqlConfig.insertRecord(sTable, rd); + } + catch (TC_Mysql_Exception& ex) + { + string err = string(ex.what()); + if (std::string::npos != err.find("doesn't exist")) + { + creatTb(sTable); + } + else + { + string sInfo = string("insert2Db exception") + "|" + ServerConfig::LocalIp + "|" + ServerConfig::Application + "." + ServerConfig::ServerName; + TARS_NOTIFY_ERROR(sInfo); + } + TLOGERROR("NotifyImp::reportNotifyInfo insert2Db exception:" << ex.what() << endl); + } + catch (exception& ex) + { + TLOGERROR("NotifyImp::reportNotifyInfo insert2Db exception:" << ex.what() << endl); + string sInfo = string("insert2Db exception") + "|" + ServerConfig::LocalIp + "|" + ServerConfig::Application + "." + ServerConfig::ServerName; + //TARS_NOTIFY_ERROR(sInfo); + } + } + case (NOTIFY): + { + TLOGDEBUG("NotifyImp::reportNotifyInfo notifyServer:" << info.sApp + "." + info.sServer << "|sSet:" << info.sSet << "|sContainer:" << info.sContainer << "|ip:" << current->getIp() + << "|eLevel:" << tars::etos(info.eLevel) << "|sMessage:" << info.sMessage << endl); + + if (info.eLevel == NOTIFYERROR) + { + // FDLOG("NOTIFYERROR") << "NotifyImp::reportNotifyInfo notifyServer:" << info.sApp + "." + info.sServer << "|sSet:" << info.sSet << "|sContainer:" << info.sContainer << "|ip:" << current->getIp() + // << "|eLevel:" << tars::etos(info.eLevel) << "|sMessage:" << info.sMessage << endl; + } + else + { + // DLOG << "NotifyImp::reportNotifyInfo notifyServer:" << info.sApp + "." + info.sServer << "|sSet:" << info.sSet << "|sContainer:" << info.sContainer << "|ip:" << current->getIp() + // << "|eLevel:" << tars::etos(info.eLevel) << "|sMessage:" << info.sMessage << endl; + } + + string sServerId = info.sApp + info.sServer + "_" + current->getIp(); + + NotifyKey stKey0; + stKey0.name = info.sApp + info.sServer; + stKey0.ip = current->getIp(); + stKey0.page = 0; + + NotifyInfo stInfo0; + + NotifyItem stItem; + stItem.sTimeStamp = TC_Common::now2str("%Y-%m-%d %H:%M:%S"); + stItem.sServerId = sServerId; + stItem.iLevel = info.eLevel; + stItem.sMessage = info.sMessage; + + int iRet; + iRet = g_notifyHash->get(stKey0, stInfo0); + TLOGDEBUG("get " << sServerId << " page " << stKey0.page << " info return :" << iRet << endl); + if (iRet == TC_HashMap::RT_LOAD_DATA_ERR) + { + return; + } + + if (stInfo0.notifyItems.size() < _maxPageSize) + { + stInfo0.notifyItems.push_back(stItem); + iRet = g_notifyHash->set(stKey0, stInfo0); + TLOGDEBUG("NotifyImp::reportNotifyInfo set sServerId:" << sServerId << "|page:" << stKey0.page << "|iRet:" << iRet << endl); + return; + } + + //0页置换出去 + NotifyKey stKeyReplPage = stKey0; + stKeyReplPage.page = (stInfo0.nextpage + 1) % _maxPageNum; + if (stKeyReplPage.page == 0) + { + stKeyReplPage.page = 1; + } + iRet = g_notifyHash->set(stKeyReplPage, stInfo0); + + //修改0页 + stInfo0.nextpage = stKeyReplPage.page; + stInfo0.notifyItems.clear(); + stInfo0.notifyItems.push_back(stItem); + iRet = g_notifyHash->set(stKey0, stInfo0); + } + default: + break; + } + + return; +} diff --git a/NotifyServer/NotifyImp.h b/NotifyServer/NotifyImp.h new file mode 100644 index 00000000..fd7b7f65 --- /dev/null +++ b/NotifyServer/NotifyImp.h @@ -0,0 +1,106 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef NOTIFY_I_H +#define NOTIFY_I_H + +#include "NotifyF.h" +#include "util/tc_common.h" +#include "util/tc_config.h" +#include "util/tc_mysql.h" +#include "servant/TarsLogger.h" +#include "LoadDbThread.h" + +using namespace tars; + +class NotifyImp : public Notify +{ +public: + /** + * 初始化 + * + * @return int + */ + virtual void initialize(); + + /** + * 退出 + */ + virtual void destroy() {}; + + /** + * report + * @param sServerName + * @param sThreadId + * @param sResult + * @param current + */ + virtual void reportServer(const string& sServerName, const string& sThreadId, const string& sResult, tars::TarsCurrentPtr current); + + /** + * notify + * @param sServerName + * @param sThreadId + * @param sCommand + * @param sResult + * @param current + */ + virtual void notifyServer(const string& sServerName, NOTIFYLEVEL level, const string& sMessage, tars::TarsCurrentPtr current); + + /** + * get notify info + */ + virtual tars::Int32 getNotifyInfo(const tars::NotifyKey & stKey,tars::NotifyInfo &stInfo,tars::TarsCurrentPtr current); + + /* + *reportNotifyInfo + *@param info + */ + virtual void reportNotifyInfo(const tars::ReportInfo & info, tars::TarsCurrentPtr current); + +protected: + + void loadconf(); + +private: + + bool IsdbTableExist(const string& sTbName); + + void creatTb(const string &sTbName); + + bool IsNeedFilte(const string& sServerName,const string& sResult); + +protected: + TC_Mysql _mysqlConfig; + string _sql; //创建表 + size_t _maxPageSize; + size_t _maxPageNum; + /* + * 按模块配置过滤规则 + * key=default 表示全局规则 + * key=app.server具体模块规则 + * 模块规则匹配失败才匹配全局规则 + + + default=r1|r2 + MTT.HelloServer=r3|r4 + + + */ + map > _setFilter; +}; + +#endif diff --git a/NotifyServer/NotifyServer.cpp b/NotifyServer/NotifyServer.cpp new file mode 100644 index 00000000..14759d89 --- /dev/null +++ b/NotifyServer/NotifyServer.cpp @@ -0,0 +1,55 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "NotifyServer.h" +#include "NotifyImp.h" +#include "jmem/jmem_hashmap.h" + +TarsHashMap * g_notifyHash; + +void NotifyServer::initialize() +{ + //增加对象 + addServant(ServerConfig::Application + "." + ServerConfig::ServerName + ".NotifyObj"); + + //初始化hash + g_notifyHash = new TarsHashMap(); + + g_notifyHash->initDataBlockSize(TC_Common::strto((*g_pconf)["/tars/hash"]), + TC_Common::strto((*g_pconf)["/tars/hash"]), + TC_Common::strto((*g_pconf)["/tars/hash"])); + + size_t iSize = TC_Common::toSize((*g_pconf)["/tars/hash"], 1024 * 1024 * 10); + if (iSize > 1024 * 1024 * 100) + iSize = 1024 * 1024 * 100; + char* data = new char[iSize]; + g_notifyHash->create(data, iSize); + + _loadDbThread = new LoadDbThread(); + _loadDbThread->init(); + _loadDbThread->start(); +} + +void NotifyServer::destroyApp() +{ + if(_loadDbThread != NULL) + { + delete _loadDbThread; + _loadDbThread = NULL; + } + + TLOGDEBUG("NotifyServer::destroyApp ok" << endl); +} diff --git a/NotifyServer/NotifyServer.h b/NotifyServer/NotifyServer.h new file mode 100644 index 00000000..94e388ae --- /dev/null +++ b/NotifyServer/NotifyServer.h @@ -0,0 +1,52 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __NOTIFY_SERVER_H_ +#define __NOTIFY_SERVER_H_ + +#include "servant/Application.h" +#include "LoadDbThread.h" + +using namespace tars; + +class NotifyServer : public Application +{ +public: + /** + * 初始化, 只会进程调用一次 + */ + virtual void initialize(); + + /** + * 析构, 每个进程都会调用一次 + */ + virtual void destroyApp(); + + /** + * 获取加载db的线程类 + */ + inline LoadDbThread * getLoadDbThread() { return _loadDbThread; } + +private: + + LoadDbThread *_loadDbThread; +}; + +extern NotifyServer g_app; +extern TC_Config * g_pconf; + +#endif + diff --git a/NotifyServer/main.cpp b/NotifyServer/main.cpp new file mode 100644 index 00000000..1e3e720d --- /dev/null +++ b/NotifyServer/main.cpp @@ -0,0 +1,42 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "NotifyServer.h" +#include + +using namespace tars; + +TC_Config * g_pconf; +NotifyServer g_app; + +int main(int argc, char *argv[]) +{ + try + { + g_pconf = &g_app.getConfig(); + g_app.main(argc, argv); + + g_app.waitForShutdown(); + } + catch(exception &ex) + { + cerr<< ex.what() << endl; + } + + return 0; +} + + diff --git a/PatchServer/CMakeLists.txt b/PatchServer/CMakeLists.txt new file mode 100644 index 00000000..b9474a3d --- /dev/null +++ b/PatchServer/CMakeLists.txt @@ -0,0 +1,8 @@ + +set(MODULE "tarspatch") + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/deploy/${MODULE}/bin) + +#complice_module(${MODULE} "Patch.tars") +complice_module(${MODULE}) + diff --git a/PatchServer/PatchCache.cpp b/PatchServer/PatchCache.cpp new file mode 100644 index 00000000..5f7c6ff2 --- /dev/null +++ b/PatchServer/PatchCache.cpp @@ -0,0 +1,279 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include +#include +#include "PatchCache.h" +#include "PatchServer.h" + +using namespace tars; + +int PatchCache::load(const std::string & sFile, std::pair & mem) +{ + TLOGDEBUG("PatchCache::load sFile:" << sFile << endl); + + struct MemState * cur = NULL; + + TC_ThreadLock::Lock lock(_mutex); + + try + { + struct stat st; + memset(&st, 0, sizeof(struct stat)); + + if (lstat(sFile.c_str(), &st) != 0) + { + TLOGERROR("PatchCache::load sFile:" << sFile << "|lstat file error:" << strerror(errno) << endl); + return -1; + } + + if ((size_t)st.st_size > _MemMax || (size_t)st.st_size < _MemMin) + { + TLOGERROR("PatchCache::load sFile:" << sFile << "|invalid file size must(" << _MemMax << ">" << st.st_size << "<" << _MemMin << ")" << endl); + return -1; + } + + //查看是否已经加载入内存 + std::map::iterator it = _mapFiles.find(sFile); + if (it != _mapFiles.end()) + { + cur = it->second; + + if ((cur->MemLoad == EM_LOADING || cur->MemLoad == EM_RELOAD))//错误都为1状态 + { + TLOGERROR("PatchCache::load sFile:" << sFile << "|loading file now|MemLoad:" << cur->MemLoad << "|MemCount:" << cur->MemCount << "|FileName:" << cur->FileName << endl); + + //这里是由于内存分配不足,导致出现loading的状态 + _mapFiles.erase(sFile); + + return -1; + } + + if (cur->FileSize == (size_t)st.st_size && cur->FileTime == st.st_mtime && cur->FileInode == st.st_ino) + { + mem.first = cur->MemBuf; + mem.second = cur->FileSize; + cur->MemTime = time(NULL); + cur->MemCount++; + + TLOGDEBUG("PatchCache::load sFile:" << sFile << "|reuse file in mem" << endl); + return 0; + } + else + { + cur->FileSize = st.st_size; + cur->FileInode = st.st_ino; + cur->FileTime = st.st_mtime; + cur->MemLoad = EM_RELOAD; + + mem.first = cur->MemBuf; + mem.second = st.st_size; + + TLOGDEBUG("PatchCache::load sFile:" << sFile << "|need reload file" << endl); + } + } + else + { + if (__getMem(sFile, cur) == -1) + { + TLOGERROR("PatchCache::load sFile:" << sFile << "|get free mem fault" << endl); + return -1; + } + + cur->FileName = sFile; + cur->FileSize = st.st_size; + cur->FileInode = st.st_ino; + cur->FileTime = st.st_mtime; + + mem.first = cur->MemBuf; + mem.second = cur->FileSize; + + if (_mapFiles.find(sFile) == _mapFiles.end()) + { + _mapFiles.insert(make_pair(sFile,cur)); + } + } + } + catch (std::exception & ex) + { + TLOGERROR("PatchCache::load sFile:" << sFile << "|exception:" << ex.what() << endl); + return -1; + } + catch (...) + { + TLOGERROR("PatchCache::load sFile:" << sFile << "|unknown Exception" << endl); + return -1; + } + + if (__loadFile(sFile, cur->MemBuf, cur->FileSize) == 0) + { + cur->MemCount++; + cur->MemTime = time(NULL); + cur->MemLoad = EM_LOADED; + + return 0; + } + else + { + cur->MemTime = 0; + cur->MemLoad = EM_NLOAD; + return -1; + } + + return -1; +} + +int PatchCache::release(const std::string & sFile) +{ + TLOGDEBUG("PatchCache::release sFile:" << sFile << endl); + + try + { + TC_ThreadLock::Lock lock(_mutex); + + std::map::iterator it = _mapFiles.find(sFile); + if (it == _mapFiles.end()) + { + TLOGERROR("PatchCache::release Find '" << sFile << "' fault" << endl); + return -1; + } + + it->second->MemCount--; + + TLOGDEBUG("PatchCache::release sFile:" << sFile << "|count:" << it->second->MemCount << endl); + return 0; + } + catch (std::exception & ex) + { + TLOGERROR("PatchCache::release sFile:" << sFile << "|exception:" << ex.what() << endl); + } + catch (...) + { + TLOGERROR("PatchCache::release sFile:" << sFile << "|unknown Exception" << endl); + } + + return -1; +} + +int PatchCache::__getMem(const std::string & sFile, struct MemState *& cur) +{ + TLOGDEBUG("PatchCache::__getMem sFile:" << sFile << endl); + + cur = NULL; + + for (size_t i = 0; i < _vecMems.size(); i++) + { + struct MemState * st = _vecMems[i]; + + TLOGDEBUG("PatchCache::__getMem sFile:" << sFile << "|MemLoad:"<MemLoad << "|MemCount:" << st->MemCount << "|MemTime:" << st->MemTime << "|FileName:" << st->FileName << endl); + + if ((st->MemLoad == EM_NLOAD || st->MemLoad == EM_LOADED) && st->MemCount == 0 && st->MemTime + g_app.getExpireTime() <= time(NULL)) + { + _mapFiles.erase(_vecMems[i]->FileName); + + cur = _vecMems[i]; + break; + } + } + + if (cur == NULL && _vecMems.size() < _MemNum) + { + cur = new MemState(); + cur->MemBuf = (char *)malloc(_MemMax);//从这里开始新建 + + _vecMems.push_back(cur); + + _mapFiles.insert(std::make_pair(sFile, cur)); + } + + if (cur != NULL) + { + cur->MemCount = 0; + cur->MemSize = _MemMax; + cur->MemLoad = EM_LOADING; + + if (cur->MemBuf == NULL)//有可能内存分配失败 + { + //从vector删除新的分配内存失败的元素 + _vecMems.erase(remove(_vecMems.begin(),_vecMems.end(),cur)); + + TLOGERROR("PatchCache::__getMem sFile:" << sFile << "|cur->MemBuf NULL" << endl); + + return -1; + } + + return 0; + } + + TLOGERROR("PatchCache::__getMem sFile:" << sFile << "|not enough mem" << endl); + + return -1; +} + +int PatchCache::__loadFile(const std::string & sFile, char * szBuff, size_t sizeLen) +{ + TLOGDEBUG("PatchCache::__loadFile sFile:" << sFile << "|sizeLen:" << sizeLen << endl); + + if(szBuff == NULL) + { + TLOGERROR("PatchCache::__loadFile sFile:" << sFile << "|sizeLen:" << sizeLen << "|szBuff NULL"<< endl); + + return -4; + } + + FILE * fp = fopen(sFile.c_str(), "r"); + if (fp == NULL) + { + TLOGERROR("PatchCache::__loadFile sFile:" << sFile << "|sizeLen:" << sizeLen << "|open file error:" << strerror(errno) << endl); + return -1; + } + + //从指定位置开始读数据 + if (fseek(fp, 0, SEEK_SET) == -1) + { + fclose(fp); + + TLOGERROR("PatchCache::__loadFile sFile:" << sFile << "|sizeLen:" << sizeLen << "|fseek error:" << strerror(errno) << endl); + return -2; + } + + //开始读取文件 + size_t r = fread(szBuff, 1, sizeLen, fp); + if (r > 0) + { + //成功读取r字节数据 + fclose(fp); + TLOGDEBUG("PatchCache::__loadFile sFile:" << sFile << "|sizeLen:" << sizeLen << "|r:" << r << endl); + return 0; + } + else + { + //到文件末尾了 + if (feof(fp)) + { + fclose(fp); + TLOGDEBUG("PatchCache::__loadFile sFile:" << sFile << "|sizeLen:" << sizeLen << "|to tail ok" << endl); + return 1; + } + + //读取文件出错了 + TLOGERROR("PatchCache::__loadFile sFile:" << sFile << "|sizeLen:" << sizeLen << "|r:" << r << "|error:" << strerror(errno) << endl); + fclose(fp); + return -3; + } + +} + diff --git a/PatchServer/PatchCache.h b/PatchServer/PatchCache.h new file mode 100644 index 00000000..e0ae6857 --- /dev/null +++ b/PatchServer/PatchCache.h @@ -0,0 +1,84 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __PATCH_CACHE_H_ +#define __PATCH_CACHE_H_ + +#include +#include +#include +#include "util/tc_monitor.h" + +const size_t SIZE_BUMEM_MIN = 1 * 1024 * 1024; +const size_t SIZE_BUMEM_MAX = 100 * 1024 * 1024; + +class PatchCache +{ +private: + enum FileLoad + { + EM_NLOAD = 0, + EM_LOADING = 1, + EM_RELOAD = 2, + EM_LOADED = 3 + }; + + struct MemState + { + string FileName; //文件路径 + size_t FileSize; //文件大小 + size_t FileInode; //Inode索引号 + time_t FileTime; //文件创建时间 + + char * MemBuf; //该块内存的起始地址 + size_t MemSize; //该块内存的大小 + size_t MemCount; //指向该块内存的数目 + time_t MemTime; //该块内存最后操纵时间 + FileLoad MemLoad; //该块内存已经加载成功 + }; +public: + void setMemOption(const size_t MemMax, const size_t MemMin, const size_t MemNum) + { + _MemMax = MemMax > SIZE_BUMEM_MAX ? SIZE_BUMEM_MAX : MemMax; + _MemMin = MemMin < SIZE_BUMEM_MIN ? SIZE_BUMEM_MIN : MemMin; + _MemNum = MemNum; + } + + int load(const std::string & sFile, std::pair & mem); + + int release(const std::string & sFile); + +private: + int __loadFile(const std::string & sFile, char * szBuff, size_t sizeLen); + + int __getMem (const std::string & sFile, struct MemState *& cur); + +private: + tars::TC_ThreadLock _mutex; + + std::vector _vecMems; + + std::map _mapFiles; + + size_t _MemMax; + + size_t _MemMin; + + size_t _MemNum; +}; + +#endif + diff --git a/PatchServer/PatchImp.cpp b/PatchServer/PatchImp.cpp new file mode 100644 index 00000000..fb06e871 --- /dev/null +++ b/PatchServer/PatchImp.cpp @@ -0,0 +1,283 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "util/tc_file.h" +#include "util/tc_config.h" +#include "util/tc_md5.h" +#include "servant/TarsLogger.h" +#include "PatchImp.h" +#include "PatchCache.h" +#include "PatchServer.h" + +extern PatchCache g_PatchCache; + +struct LIST +{ + LIST(const string& dir, vector &vf) : _dir(dir), _vf(vf) + { + } + + void operator()(const string &file) + { + //普通文件才同步, 连接文件有效 + if(tars::TC_File::isFileExistEx(file, S_IFREG)) + { + FileInfo fi; + fi.path = file.substr(_dir.length()); + fi.size = tars::TC_File::getFileSize(file); + fi.canExec = tars::TC_File::canExecutable(file); + fi.md5 = tars::TC_MD5::md5file(file); + + _vf.push_back(fi); + + TLOGDEBUG("LIST path:" << fi.path << "|file:" << file << "|size:" << fi.size << "|exec:" << (fi.canExec?"true":"false") << endl); + } + } + + string _dir; + vector &_vf; +}; + +PatchImp::PatchImp() +: _size(1024*1024) +{ +} + +void PatchImp::initialize() +{ + try + { + _directory = (*g_conf)["/tars"]; + _uploadDirectory = (*g_conf)["/tars"]; + _size = TC_Common::toSize(g_conf->get("/tars", "1M"), 1024*1024); + } + catch(exception &ex) + { + TLOGDEBUG("PatchImp::initialize directory must not be empty." << endl); + exit(0); + } + + if(!tars::TC_File::isAbsolute(_directory)) + { + TLOGDEBUG("PatchImp::initialize directory must be absolute directory path." << endl); + exit(0); + } + + TLOGDEBUG("PatchImp::initialize patch dirtectory:" << _directory << "|uploadDirectory:" << _uploadDirectory << "|size:" << _size << endl); +} + + +/************************************************************************************************** + ** 对外接口,普通下载接口 + ** + **/ +int PatchImp::listFileInfo(const string &path, vector & vf, TarsCurrentPtr current) +{ + TLOGDEBUG("PatchImp::listFileInfo ip:" << current->getIp() << "|path:" << path << endl); + + string dir = tars::TC_File::simplifyDirectory(_directory + "/" + path); + + int ret = __listFileInfo(dir, vf); + + stringstream ss; + tars::TarsDisplayer ds(ss); + ds.displaySimple(vf, false); + + TLOGDEBUG("PatchImp::listFileInfo ip:" << current->getIp() << "|path:" << path << "|dir:" << dir << "|str:" << ss.str() << endl); + + return ret; +} + +int PatchImp::download(const string & file, int pos, vector & vb, TarsCurrentPtr current) +{ + TLOGDEBUG("PatchImp::download ip:" << current->getIp() << "|file:" << file << "|pos:" << pos << endl); + + string path = tars::TC_File::simplifyDirectory(_directory + "/" + file); + + int iRet = -1; + + if (iRet < 0) + { + iRet = __downloadFromMem (path, pos, vb); + } + + if (iRet < 0) + { + iRet = __downloadFromFile(path, pos, vb); + } + + return iRet; +} + +int PatchImp::preparePatchFile(const string &app, const string &serverName, const string &patchFile, TarsCurrentPtr current) +{ + string upfile = _uploadDirectory + "/" + app + "/" + serverName + "/" + patchFile; + string dstDirectory = _directory + "/TARSBatchPatching/" + app + "/" + serverName; + string dstfile = dstDirectory + "/" + app +"." + serverName + ".tgz"; + + TLOGDEBUG("PatchImp::preparePatchFile upfile:" << upfile << "|dstfile:" << dstfile << endl); + + bool succ = TC_File::makeDirRecursive(dstDirectory); + if (!succ) + { + TLOGERROR("PatchImp::preparePatchFile makeDirRecursive path:" << dstDirectory << "|error!" << endl); + return -2; + } + + if (!TC_File::isFileExist(upfile)) + { + TLOGERROR("PatchImp::preparePatchFile isFileExist file:" << upfile << "|not exist!" << endl); + return -1; + } + + TC_File::copyFile(upfile, dstfile, true); + + return 0; +} + +/************************************************************************************************** + * 发布服务内部使用函数 + */ +int PatchImp::__listFileInfo(const string &path, vector &vf) +{ + TLOGDEBUG("PatchImp::__listFileInfo patch:" << path << endl); + + if (path.find("..") != string::npos) + { + return -1; + } + + if(!tars::TC_File::isFileExistEx(path, S_IFDIR)) + { + //是文件 + FileInfo fi; + fi.path = tars::TC_File::extractFileName(path); + fi.size = tars::TC_File::getFileSize(path); + fi.canExec = tars::TC_File::canExecutable(path); + fi.md5 = tars::TC_MD5::md5file(path); + + vf.push_back(fi); + + return 1; + } + else + { + //目录 + vector files; + + tars::TC_File::listDirectory(path, files, true); + + for_each(files.begin(), files.end(), LIST(path, vf)); + + return 0; + } + + return 0; +} + +int PatchImp::__downloadFromMem (const string & file, size_t pos, vector & vb) +{ + TLOGDEBUG("PatchImp::__downloadFromMem file:" << file << "|pos:" << pos << "|size:" << _size << endl); + + pair mem; + if (g_PatchCache.load(file, mem) != 0) + { + TLOGERROR("PatchImp::__downloadFromMem file:" << file << "|pos:" << pos << "|LoadFile error" << endl); + return -1; + } + + if (pos >= mem.second) + { + TLOGDEBUG("PatchImp::__downloadFromMem file:" << file << "|pos:" << pos << "|to tail ok" << endl); + + g_PatchCache.release(file); + + return 1; + } + + const size_t sizeBuf = mem.second - pos >= _size ? _size : mem.second - pos; + + TLOGDEBUG("PatchImp::__downloadFromMem file:" << file << "|pos:" << pos << "|sizeBuf:" << sizeBuf << endl); + + vb.resize(sizeBuf); + + memcpy((char *)&vb[0], mem.first + pos, sizeBuf); + + g_PatchCache.release(file); + + return 0; +} + + +int PatchImp::__downloadFromFile(const string & file, size_t pos, vector & vb) +{ + TLOGDEBUG("PatchImp::__downloadFromFile file:" << file << "|pos:" << pos << "|size:" << _size << endl); + + FILE * fp = fopen(file.c_str(), "rb"); + if (fp == NULL) + { + TLOGERROR("PatchImp::__downloadFromFile file:" << file << "|pos:" << pos << "|open file error:" << strerror(errno) << endl); + return -1; + } + + //从指定位置开始读数据 + if (fseek(fp, pos, SEEK_SET) == -1) + { + fclose(fp); + + TLOGERROR("PatchImp::__downloadFromFile file:" << file << "|pos:" << pos << "|fseek error:" << strerror(errno) << endl); + return -2; + } + + //开始读取文件 + vb.resize(_size); + size_t r = fread((void*)(&vb[0]), 1, _size, fp); + if (r > 0) + { + //成功读取r字节数据 + vb.resize(r); + + fclose(fp); + + TLOGDEBUG("PatchImp::__downloadFromFile file:" << file << "|pos:" << pos << "|r:" << r << endl); + + return 0; + } + else + { + //到文件末尾了 + if (feof(fp)) + { + fclose(fp); + + TLOGDEBUG("PatchImp::__downloadFromFile file:" << file << "|pos:" << pos << "|to tail ok" << endl); + + return 1; + } + + //读取文件出错了 + TLOGERROR("PatchImp::__downloadFromFile file:" << file << "|pos:" << pos << "|r:" << r << "|error:" << strerror(errno) << endl); + + fclose(fp); + + return -3; + } + +} + + + + diff --git a/PatchServer/PatchImp.h b/PatchServer/PatchImp.h new file mode 100644 index 00000000..2e80b84d --- /dev/null +++ b/PatchServer/PatchImp.h @@ -0,0 +1,93 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __PATCH_IMP_H_ +#define __PATCH_IMP_H_ + +#include "Patch.h" + +using namespace tars; + +class PatchImp : public Patch +{ +public: + /** + * + */ + PatchImp(); + + /** + * 初始化 + * + * @return int + */ + virtual void initialize(); + + /** + * 退出 + */ + virtual void destroy() {}; + + /** + * 获取路径下所有文件列表信息 + * @param path, 目录路径, 相对_directory的路径, 不能有.. + * @param vector, 文件列表信息 + * @return int + */ + int listFileInfo(const string &path, vector &vf, TarsCurrentPtr current); + + /** + * 下载文件 + * @param file, 文件完全路径 + * @param pos, 从什么位置开始下载 + * @return vector, 文件内容 + */ + int download(const string &file, int pos, vector &vb, TarsCurrentPtr current); + + /** + * 准备好需要patch的文件,将发布的文件从上传目录复制到发布目录 + * @param app, 应用名 + * @param serverName, 服务名 + * @param patchFile, 需要发布的文件名 + * @return int, 0: 成功, <0: 失败 + */ + int preparePatchFile(const string &app, const string &serverName, const string &patchFile, TarsCurrentPtr current); + +protected: + int __listFileInfo(const string &path, vector &vf); + + int __downloadFromMem (const string & file, size_t pos, vector & vb); + + int __downloadFromFile(const string & file, size_t pos, vector & vb); + +protected: + /** + * 目录 + */ + string _directory; + + /** + * 上传的目录 + */ + string _uploadDirectory; + + /** + * 每次同步大小 + */ + size_t _size; +}; + +#endif diff --git a/PatchServer/PatchServer.cpp b/PatchServer/PatchServer.cpp new file mode 100644 index 00000000..659aca88 --- /dev/null +++ b/PatchServer/PatchServer.cpp @@ -0,0 +1,47 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "PatchServer.h" +#include "PatchImp.h" +#include "PatchCache.h" + +PatchCache g_PatchCache; + +void PatchServer::initialize() +{ + //增加对象 + addServant(ServerConfig::Application + "." + ServerConfig::ServerName +".PatchObj"); + + size_t memMax = TC_Common::toSize(g_conf->get("/tars", "100M"), 1024*1024); + size_t memMin = TC_Common::toSize(g_conf->get("/tars", "1M"), 1024*1024); + size_t memNum = TC_Common::strto(g_conf->get("/tars", "10")); + + g_PatchCache.setMemOption(memMax, memMin, memNum); + + int _expireTime = TC_Common::strto(g_conf->get("/tars", "30")); + + TLOGDEBUG("PatchServer::initialize memMax:" << memMax << "|memMin:" << memMin << "|memNum:" << memNum << "|expireTime:" << _expireTime << endl); +} + +void PatchServer::destroyApp() +{ + TLOGDEBUG("PatchServer::destroyApp ok" << endl); +} + +int PatchServer::getExpireTime() const +{ + return _expireTime; +} diff --git a/PatchServer/PatchServer.h b/PatchServer/PatchServer.h new file mode 100644 index 00000000..37788668 --- /dev/null +++ b/PatchServer/PatchServer.h @@ -0,0 +1,49 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __PATCH_SERVER_H_ +#define __PATCH_SERVER_H_ + +#include "servant/Application.h" +#include "Patch.h" + +using namespace tars; + +class PatchServer : public Application +{ +protected: + /** + * 初始化, 只会进程调用一次 + */ + virtual void initialize(); + + /** + * 析够, 进程退出时会调用一次 + */ + virtual void destroyApp(); + +public: + int getExpireTime() const; + +private: + //文件的内存缓存的过期时间 + int _expireTime; +}; + +extern TC_Config *g_conf; +extern PatchServer g_app; + +#endif diff --git a/PatchServer/main.cpp b/PatchServer/main.cpp new file mode 100644 index 00000000..d1b12a75 --- /dev/null +++ b/PatchServer/main.cpp @@ -0,0 +1,51 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "PatchServer.h" +#include + +using namespace std; + +TC_Config *g_conf; +PatchServer g_app; +/** + * 说明 + * 1 需要配置一个路径 + * 2 如果子目录是link目录, 则不进入link目录遍历 + * 3 如果文件是link, 则读取link的文件 + * 4 如果同步的文件是link目录, 则进入link目录遍历, 下面的规则如1 + * @param argc + * @param argv + * + * @return int + */ +int main(int argc, char *argv[]) +{ + try + { + g_conf = &g_app.getConfig(); + g_app.main(argc, argv); + g_app.waitForShutdown(); + } + catch(exception &ex) + { + cout << ex.what() << endl; + } + + return 0; +} + + diff --git a/PropertyServer/CMakeLists.txt b/PropertyServer/CMakeLists.txt new file mode 100644 index 00000000..b39a690d --- /dev/null +++ b/PropertyServer/CMakeLists.txt @@ -0,0 +1,6 @@ + +set(MODULE "tarsproperty") + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/deploy/${MODULE}/) + +complice_module(${MODULE}) diff --git a/PropertyServer/PropertyDbManager.cpp b/PropertyServer/PropertyDbManager.cpp new file mode 100644 index 00000000..f9a7f39b --- /dev/null +++ b/PropertyServer/PropertyDbManager.cpp @@ -0,0 +1,655 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "PropertyDbManager.h" +#include "PropertyReapThread.h" +#include "util/tc_config.h" +#include "PropertyServer.h" +#include "PropertyHashMap.h" +/////////////////////////////////////////////////////////// +// + +PropertyDbManager::PropertyDbManager() +: _terminate(false) +{ + TLOGDEBUG("begin PropertyDbManager init" << endl); + + _sql = (*g_pconf)["/tars"]; + _sqlStatus = g_pconf->get("/tars", ""); + _reapSql = g_pconf->getDomainMap("/tars/reapSql"); + _tbNamePre = g_pconf->get("/tars/db","t_property_realtime_"); + _maxInsertCount = TC_Common::strto(g_pconf->get("/tars/reapSql","1000")); + _enableWeighted = TC_Common::strto(g_pconf->get("/tars/","0")); + + if (_sqlStatus == "") + { + _sqlStatus = "CREATE TABLE `t_ecstatus` ( " + " `id` int(11) NOT NULL auto_increment, " + " `appname` varchar(64) NOT NULL default '', " + " `action` tinyint(4) NOT NULL default '0', " + " `checkint` smallint(6) NOT NULL default '10', " + " `lasttime` varchar(16) NOT NULL default '', " + " PRIMARY KEY (`appname`,`action`), " + " UNIQUE KEY `id` (`id`) " + " ) ENGINE=HEAP DEFAULT CHARSET=gbk"; + } + + string sCutType = g_pconf->get("/tars/reapSql","hour"); + if (sCutType == "day") + { + _cutType = CUT_BY_DAY; + } + else if (sCutType == "minute") + { + _cutType = CUT_BY_MINUTE; + } + else + { + _cutType = CUT_BY_HOUR; + } + + size_t iInsertThreadByMachine = TC_Common::strto(g_pconf->get("/tars/reapSql","4")); + size_t iInsertThreadByDB = TC_Common::strto(g_pconf->get("/tars/reapSql","2")); + + TLOGDEBUG("PropertyDbManager init iInsertThreadByMachine:" << iInsertThreadByMachine << "|iInsertThreadByDB:" << iInsertThreadByDB << endl); + + vector vDb =g_pconf->getDomainVector("/tars/multidb"); + + _dbNumber = vDb.size(); + + TLOGDEBUG("PropertyDbManager init multidb size:" <<_dbNumber << endl); + + //map mIp; + map > mIp; + vector vIp; + string sIp(""); + string sIpAndPort(""); + + for (int i=0; i< _dbNumber; i++) + { + TC_DBConf tConf; + tConf.loadFromMap(g_pconf->getDomainMap("/tars/multidb/" + vDb[i])); + _sTbNamePre.push_back(g_pconf->get("/tars/multidb/" + vDb[i] + "", + "t_propert_0" + TC_Common::tostr(i) + "_")); + + sIp = tConf._host; + + sIpAndPort = "ip:"; + sIpAndPort += tConf._host; + sIpAndPort += "|port:"; + sIpAndPort += TC_Common::tostr(tConf._port); + + _ipAndPort.push_back(sIpAndPort); + + map >::const_iterator iter = mIp.find(sIp); + + if(iter == mIp.end()) + { + pair tempPair; + tempPair.first = 0; + tempPair.second = 0; + + //mIp.insert(map::value_type(sIp, 0)); + mIp.insert(map >::value_type(sIp, tempPair)); + + _dbIpNum++; + + vector vIndex; + vIndex.push_back(i); + + _ipHasDbInfo.insert(map >::value_type(sIp, vIndex)); + } + else + { + _ipHasDbInfo[sIp].push_back(i); + } + + vIp.push_back(sIp); + + //默认值为1 + _dbWeighted.push_back(TC_Common::strto(g_pconf->get("/tars/multidb/" + vDb[i] + "","1"))); + + TC_Mysql *pMysql = new TC_Mysql(); + pMysql->init(tConf); + _ssdThreadMysql.push_back(pMysql); + } + + if(iInsertThreadByMachine < _dbIpNum) + { + _dbIpNum = iInsertThreadByMachine; + } + + TLOGDEBUG("PropertyDbManager init insert DB threadnum:" << _dbIpNum << endl); + + size_t iDbOneMachine = 999999; + map >::iterator m_iter = _ipHasDbInfo.begin(); + while(m_iter != _ipHasDbInfo.end()) + { + vector &vDb = m_iter->second; + + if(vDb.size() < iDbOneMachine) + { + iDbOneMachine = vDb.size(); + } + ++m_iter; + } + + TLOGDEBUG("PropertyDbManager init iDbOneMachine:" << iDbOneMachine << endl); + + if(iInsertThreadByDB > iDbOneMachine) + { + iInsertThreadByDB = iDbOneMachine; + } + + _oneDbHasThreadNum = iInsertThreadByDB; + + TLOGDEBUG("PropertyDbManager init iInsertThreadByDB:" << iInsertThreadByDB << endl); + + size_t iIndex = 0; + map >::iterator map_it = mIp.begin(); + + while(map_it != mIp.end()) + { + map_it->second.first = iIndex; + map_it->second.second = 0; + ++iIndex; + + if(iIndex == _dbIpNum) + { + iIndex = 0; + } + + ++map_it; + } + + for(size_t i = 0; i < vIp.size(); ++i) + { + map >::iterator iter = mIp.find(vIp[i]); + if(iter != mIp.end()) + { + _dbToIp.insert(map::value_type(i, (iter->second.first * iInsertThreadByDB + iter->second.second))); + + iter->second.second += 1; + + if(iter->second.second == iInsertThreadByDB) + { + iter->second.second = 0; + } + } + else + { + TLOGERROR("PropertyDbManager init DbToIp error ip:" << vIp[i] << endl); + } + } + + map::iterator mDbToIpIter = _dbToIp.begin(); + while(mDbToIpIter != _dbToIp.end()) + { + TLOGDEBUG("PropertyDbManager init index:" << mDbToIpIter->first << "|thread index:" << mDbToIpIter->second << endl); + ++mDbToIpIter; + } + + map >::iterator m_iter1 = _ipHasDbInfo.begin(); + while(m_iter1 != _ipHasDbInfo.end()) + { + vector &vDb = m_iter1->second; + + FDLOG("PropertyPool") << "statsec ip:" << ServerConfig::LocalIp << "|ip:" << m_iter1->first << "|DbNum:" << vDb.size() << endl; + + ++m_iter1; + } + + TLOGDEBUG("PropertyDbManager init ok." << endl); +} +/////////////////////////////////////////////////////////// +PropertyDbManager::~PropertyDbManager() +{ + vector::iterator it = _ssdThreadMysql.begin(); + while(it != _ssdThreadMysql.end()) + { + if(*it) + { + delete *it; + } + ++it; + } +} +/////////////////////////////////////////////////////////// +size_t PropertyDbManager::getDbToIpIndex(size_t iIndex) +{ + map::const_iterator iter = _dbToIp.find(iIndex); + if(iter != _dbToIp.end()) + { + return iter->second; + } + return -1; +} +/////////////////////////////////////////////////////////// +bool PropertyDbManager::hasEnableWeighted() +{ + return _enableWeighted; +} +/////////////////////////////////////////////////////////// +string PropertyDbManager::getIpAndPort(size_t iDbIndex) +{ + assert(iDbIndex < _ipAndPort.size()); + + return _ipAndPort[iDbIndex]; +} +/////////////////////////////////////////////////////////// +void PropertyDbManager::getDbWeighted(int& iGcd,int& iMaxW,vector& vDbWeighted) +{ + vDbWeighted = _dbWeighted; + + int gcd = 0; + int iMax = 0; + for(size_t i = 0;i < vDbWeighted.size(); i++) + { + gcd = getGcd(gcd,vDbWeighted[i]); + + if(vDbWeighted[i] > iMax) + { + iMax = vDbWeighted[i]; + } + } + + iGcd = gcd; + + iMaxW = iMax; +} +/////////////////////////////////////////////////////////// +int PropertyDbManager::getGcd (int a, int b) +{ + int c; + while(a != 0) + { + c = a; + a = b%a; + b = c; + } + + return b; +} +/////////////////////////////////////////////////////////// +int PropertyDbManager::insert2Db(const PropertyMsg &mPropMsg, const string &sDate, const string &sFlag, int iOldWriteNum, int &iNowWriteNum, const string &sTbNamePre, TC_Mysql *pMysql) +{ + int iCount = 0; + int iHasWriteNum = iOldWriteNum; + ostringstream osSql; + string strValues; + + iNowWriteNum = 0; + + string strTbName = (sTbNamePre !=""?sTbNamePre:_tbNamePre) + TC_Common::replace(sDate,"-","") + sFlag.substr(0,_cutType*2); + try + { + creatTable(strTbName,pMysql); + + for(map::const_iterator it = mPropMsg.begin(); it != mPropMsg.end(); it++ ) + { + if(_terminate) + { + return -1; + } + + if(iHasWriteNum > 0) + { + --iHasWriteNum; + continue; + } + + const PropHead& head = it->first; + const PropBody& body = it->second; + //组织sql语句 + for(size_t i = 0; i < body.vInfo.size(); i++) + { + strValues = " ('"; + strValues += sDate; + strValues += "','"; + strValues += sFlag; + strValues += "','"; + strValues += pMysql->escapeString(head.moduleName); + strValues += "','"; + strValues += pMysql->escapeString(head.ip); + strValues += "','"; + strValues += pMysql->escapeString(head.propertyName); + strValues += "','"; + strValues += pMysql->escapeString(head.setName); + strValues += "','"; + strValues += pMysql->escapeString(head.setArea); + strValues += "','"; + strValues += pMysql->escapeString(head.setID); + strValues += "','"; + strValues += pMysql->escapeString(body.vInfo[i].policy); + strValues += "','"; + + //如果是平均值 + if(body.vInfo[i].policy == "Avg") + { + vector sTmp = TC_Common::sepstr(body.vInfo[i].value,"="); + double avg = 0; + if(2 == sTmp.size() && TC_Common::strto(sTmp[1]) != 0) + { + avg = TC_Common::strto(sTmp[0])/TC_Common::strto(sTmp[1]); + } + else + { + avg = TC_Common::strto(sTmp[0]); + } + + + strValues += pMysql->escapeString(TC_Common::tostr(avg)); + strValues += "') "; + } + else + { + strValues += pMysql->escapeString(body.vInfo[i].value); + strValues += "') "; + } + + if ( iCount == 0 ) + { + osSql.str(""); + osSql << "insert ignore into " + strTbName + " (f_date,f_tflag,master_name,master_ip,property_name,set_name,set_area,set_id,policy,value) values "; + osSql << strValues; + } + else + { + osSql<< "," + strValues; + } + iNowWriteNum++; + iCount ++; + } + if ( iCount >= _maxInsertCount ) + { + usleep(100); + pMysql->execute(osSql.str()); + + TLOGDEBUG("insert " << strTbName << " affected:" << iCount << endl); + + FDLOG("PropertyPool") << "propertypool ip:" << ServerConfig::LocalIp << "|insert " << strTbName << "|insert affected:" << iCount << "|mysql affected:" << pMysql->getAffectedRows() << endl; + + iCount = 0; + } + } + + if ( iCount != 0 ) + { + pMysql->execute(osSql.str()); + TLOGDEBUG("insert " << strTbName << " affected:" << iCount << endl); + FDLOG("PropertyPool") << "statsec ip:" << ServerConfig::LocalIp << "|insert " << strTbName << "|insert affected:" << iCount << "|mysql affected:" << pMysql->getAffectedRows() << endl; + } + } + catch (TC_Mysql_Exception& ex) + { + string err = string (ex.what()); + if (std::string::npos == err.find( "Duplicate")) + { + creatTable(strTbName,pMysql); + } + //因为会输出1千条记录,这里做截取 + TLOGERROR("insert2Db exception: " << err.substr(0,64) << endl); + return 1; + } + catch (exception& ex) + { + TLOGERROR("insert2Db exception: " << ex.what() << endl); + return 1; + } + return 0; +} +/////////////////////////////////////////////////////////// +int PropertyDbManager::creatTable(const string &sTbName, TC_Mysql *_pstMql) +{ + string daytime = sTbName.substr(0, sTbName.length() -2 ); // 去掉小时 + int iRet = 0; + int hour = 0; + + for (hour=0; hour < 24; hour++) + { + char buf[3]; + snprintf(buf,sizeof(buf),"%.2d",hour); + string sName = daytime + string(buf); + iRet |= creatTb(sName, _pstMql); + } + + return iRet; +} +/////////////////////////////////////////////////////////// +bool PropertyDbManager::hasdbTableExist(const string& sTbName,TC_Mysql *pMysql) +{ + try + { + TC_Mysql::MysqlData tTotalRecord = pMysql->queryRecord("show tables like '%"+sTbName+"%'"); + TLOGINFO(__FUNCTION__<<"|show tables like '%"+sTbName+"%|affected:"< 0) + { + return true; + } + else + { + return false; + } + + } + catch(TC_Mysql_Exception& ex) + { + TLOGERROR("exception: " << ex.what() << endl); + return false; + } +} +/////////////////////////////////////////////////////////// +int PropertyDbManager::creatTb(const string &sTbName,TC_Mysql *pMysql) +{ + try + { + + if (!hasdbTableExist(sTbName,pMysql)) + { + string sSql = TC_Common::replace(_sql, "${TABLE}",sTbName); + TLOGINFO(sSql << endl); + pMysql->execute(sSql); + } + + return 0; + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("PropertyDbManager::creatTb exception: " << ex.what() << endl); + return 1; + } +} +/////////////////////////////////////////////////////////// +int PropertyDbManager::creatEscTb(const string &sTbName, const string& sSql , TC_Mysql *pMysql) +{ + try + { + if (!hasdbTableExist(sTbName,pMysql)) + { + TLOGDEBUG(sSql << endl); + pMysql->execute(sSql); + + } + return 0; + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("exception: " << ex.what() << endl); + return 1; + } +} +/////////////////////////////////////////////////////////// +int PropertyDbManager::updateEcsStatus(const string &sLastTime,const string &sTbNamePre,TC_Mysql *pMysql) +{ + try + { + string sAppName = sTbNamePre != ""?sTbNamePre:_tbNamePre; + string sCondition = "where appname='"+sAppName+"' and action =0"; + + TC_Mysql::RECORD_DATA rd; + rd["lasttime"] = make_pair(TC_Mysql::DB_STR, sLastTime); + + int iRet = pMysql->updateRecord("t_ecstatus", rd,sCondition); + + TLOGDEBUG("PropertyDbManager::updateEcsStatus iRet: " <getLastSQL()<< endl); + if (iRet == 0 ) + { + rd["appname"] = make_pair(TC_Mysql::DB_STR, sAppName); + rd["checkint"] = make_pair(TC_Mysql::DB_INT, TC_Common::tostr(g_app.getInserInterv())); + rd["lasttime"] = make_pair(TC_Mysql::DB_STR, sLastTime); + iRet = pMysql->replaceRecord("t_ecstatus", rd); + } + if (iRet != 1) + { + TLOGDEBUG("PropertyDbManager::updateEcsStatus erro: ret:" << iRet<<"\n"<getLastSQL()<< endl); + } + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("PropertyDbManager::updateEcsStatus exception: " << ex.what() << endl); + creatEscTb("t_ecstatus", _sqlStatus, pMysql); + return 1; + } + return 0; +} +/////////////////////////////////////////////////////////// +int PropertyDbManager::insert2MultiDbs(int iIndex, const PropertyMsg &propertymsg, const string &sDate, const string &sFlag) +{ + try + { + string sIp = ServerConfig::LocalIp; + + string sLastTime = sDate + " " + sFlag; + + string sTbNamePre = ""; + TC_Mysql * pMysql = NULL; + + sTbNamePre = _sTbNamePre[iIndex]; + + pMysql = _ssdThreadMysql[iIndex]; + + if (checkLastTime(sLastTime, sTbNamePre + sIp, pMysql) == 0) //=0,没有记录表示: 数据库记录的时间,比当前当前时间小 + { + TLOGDEBUG("begin insert to db " << getIpAndPort(iIndex) << endl); + + int iOldWrite = 0; + int iNowWrite = 0; + + int64_t iBegin = tars::TC_TimeProvider::getInstance()->getNowMs(); + + if(insert2Db(propertymsg, sDate, sFlag, iOldWrite, iNowWrite, sTbNamePre, pMysql) != 0) + { + if(_terminate) + { + return -1; + } + + iOldWrite = iNowWrite; + iNowWrite = 0; + + if(insert2Db(propertymsg ,sDate, sFlag, iOldWrite, iNowWrite, sTbNamePre, pMysql) != 0 ) + { + if(_terminate) + { + return -1; + } + + string sMsg("insert2Db_"); + sMsg += getIpAndPort(iIndex); + + sendAlarmSMS(sMsg); + } + else + { + if(updateEcsStatus(sLastTime, sTbNamePre + sIp, pMysql) != 0) + { + string sMsg("updateEcsStatus_"); + sMsg += getIpAndPort(iIndex); + + sendAlarmSMS(sMsg); + } + } + } + else + { + if(updateEcsStatus(sLastTime, sTbNamePre + sIp, pMysql) != 0) + { + string sMsg("updateEcsStatus_"); + sMsg += getIpAndPort(iIndex); + + sendAlarmSMS(sMsg); + } + } + + int64_t iEnd = tars::TC_TimeProvider::getInstance()->getNowMs(); + + TLOGDEBUG("insert|" << iIndex << "|" << getIpAndPort(iIndex) << "|" << sDate << "|" << sFlag << "|" << propertymsg.size() << "|" << (iEnd - iBegin) << endl); + FDLOG("PropertyPool") << "propertypool ip:" << ServerConfig::LocalIp << "|insert|dbIndex:" << iIndex << "|" << getIpAndPort(iIndex) << "|date:" << sDate << "|tflag:" << sFlag + << "|records:" << propertymsg.size() << "|timecost(ms):" << (iEnd - iBegin) << "|iBegin(ms):" << iBegin << "|iEnd(ms):" << iEnd << endl; + } + } + catch(TC_Mysql_Exception& ex) + { + TLOGERROR("PropertyDbManager::insert2MultiDbs TC_Mysql_Exception: " << ex.what() << endl); + } + catch(exception& ex) + { + TLOGERROR("PropertyDbManager::insert2MultiDbs exception: " << ex.what() << endl); + } + + return 0; +} +/////////////////////////////////////////////////////////// +int PropertyDbManager::sendAlarmSMS(const string &sMsg) +{ + string errInfo = " ERROR:" + ServerConfig::LocalIp + "|" + sMsg + ":统计入库失败,请及时处理!"; + TARS_NOTIFY_ERROR(errInfo); + + TLOGERROR("TARS_NOTIFY_ERROR " << errInfo << endl); + + return 0; +} +/////////////////////////////////////////////////////////// +int PropertyDbManager::getDbNumber() +{ + return _dbNumber; +} +/////////////////////////////////////////////////////////// +int PropertyDbManager::checkLastTime(const string &sLastTime,const string &sTbNamePre,TC_Mysql *pMysql) +{ + int iRet = 0; + try + { + string sAppName = sTbNamePre != "" ? sTbNamePre : _tbNamePre; + string sCondition = "where appname='"; + sCondition += sAppName; + sCondition += "' and lasttime >= '"; + sCondition += sLastTime; + sCondition += "'" ; + + iRet = pMysql->getRecordCount("t_ecstatus", sCondition); + + TLOGDEBUG("StatDbManager::checkLastTime iRet: " <getLastSQL()<< endl); + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("StatDbManager::checkLastTime exception: " << ex.what() << endl); + creatEscTb("t_ecstatus", _sqlStatus, pMysql); + return 0; + } + + return iRet; +} diff --git a/PropertyServer/PropertyDbManager.h b/PropertyServer/PropertyDbManager.h new file mode 100644 index 00000000..88e25724 --- /dev/null +++ b/PropertyServer/PropertyDbManager.h @@ -0,0 +1,136 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __DB_MANAGER_H_ +#define __DB_MANAGER_H_ + +#include "util/tc_common.h" +#include "util/tc_thread.h" +#include "util/tc_option.h" +#include "util/tc_file.h" +#include "util/tc_mysql.h" +#include "util/tc_config.h" +#include "servant/TarsLogger.h" +#include "jmem/jmem_hashmap.h" +#include "servant/PropertyF.h" +#include "PropertyHashMap.h" + +using namespace tars; + +class PropertyDbManager : public TC_Singleton,public TC_ThreadMutex +{ +public: + enum CutType + { + CUT_BY_DAY = 0, + CUT_BY_HOUR = 1, + CUT_BY_MINUTE = 2, + }; + +public: + PropertyDbManager(); + + ~PropertyDbManager(); + +public: + + int creatTb(const string &strTbName,TC_Mysql *pMysql = NULL); + + int creatTable(const string &sTbName, TC_Mysql *_pstMql); + + int creatEscTb(const string &sTbName, const string& sSql , TC_Mysql *pMysql); + + int insert2Db(const PropertyMsg &mPropMsg,const string &sDate,const string &sFlag, int iOldWriteNum, int &iNowWriteNum,const string &sTbNamePre = "",TC_Mysql *pMysql = NULL); + + int updateEcsStatus(const string &sLastTime,const string &sTbNamePre = "",TC_Mysql *pMysql = NULL); + + int checkLastTime(const string &sLastTime,const string &sTbNamePre,TC_Mysql *pMysql); + + int insert2MultiDbs(int iIndex, const PropertyMsg &propertymsg, const string &sDate, const string &sFlag); + + int sendAlarmSMS(const string &sMsg); + + int getDbNumber(); + + int genRandOrder(); + + /** + * 获取各个db的权重值,并返回所有权重的最大公约数值和最大权重 + * @param iGcd + * @param iMaxW + * @param vDbWeighted + */ + void getDbWeighted(int& iGcd,int& iMaxW,vector& vDbWeighted); + + bool hasEnableWeighted(); + + bool hasdbTableExist(const string& sTbName,TC_Mysql *pMysql); + + size_t getDbToIpIndex(size_t iIndex); + + size_t getDbIpNum() { return _dbIpNum; } + + size_t getInsertDbThreadNum() { return _dbIpNum * _oneDbHasThreadNum; } + + string getIpAndPort(size_t iDbIndex); + + map >& getIpHasDbInfo() { return _ipHasDbInfo; } + + void setTerminateFlag(bool bFlag) { _terminate = bFlag; } + +private: + + /** + *Greatest Common Divisor + *最大公约数 + */ + int getGcd (int a, int b); + +private: + + + bool _terminate; //入库时,停止的控制开关 + string _sql; //创建表 + string _sqlStatus; //创建表t_ecstatus + string _tbNamePre; //表前缀 + int _maxInsertCount; //一次最大插入条数 + CutType _cutType; //分表类型 + int _tableInterval; + map _reapSql; //定时执行sql + + vector _ssdThreadMysql; // reapthread中使用。 + vector _sTbNamePre; + int _dbNumber; + vector _randOrder; + + //各个db的权重值 + vector _dbWeighted; + bool _enableWeighted; + + //多线程入库使用 + size_t _dbIpNum; + size_t _oneDbHasThreadNum; + map _dbToIp; + map > _ipHasDbInfo; + //打印日志使用 + vector _ipAndPort; + + +}; + +#endif + + diff --git a/PropertyServer/PropertyHashMap.h b/PropertyServer/PropertyHashMap.h new file mode 100644 index 00000000..72e6668d --- /dev/null +++ b/PropertyServer/PropertyHashMap.h @@ -0,0 +1,213 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __PROPERTY_HASHMAP_H_ +#define __PROPERTY_HASHMAP_H_ + +#include "util/tc_common.h" +#include "jmem/jmem_hashmap.h" +#include "servant/PropertyF.h" +#include "servant/TarsLogger.h" + +using namespace tars; + +typedef StatPropMsgBody PropBody; +typedef StatPropMsgHead PropHead; +typedef TarsHashMap PropHashMap; + +typedef std::map, __gnu_cxx::__pool_alloc > > PropertyMsg; + +class PropertyHashMap : public PropHashMap +{ +public: + + + /** + * 增加数据 + * @param Key + * @param Value + * + * @return int + */ + int add(const PropHead &head, const StatPropMsgBody &body) + { + int ret = TC_HashMap::RT_OK; + tars::TarsOutputStream osk; + head.writeTo(osk); + string sk(osk.getBuffer(), osk.getLength()); + { + TC_LockT lock(ThreadLockPolicy::mutex()); + string sv; + time_t t = 0; + ret = this->_t.get(sk, sv,t); + if ( ret < 0 || ret == TC_HashMap::RT_ONLY_KEY || ret == TC_HashMap::RT_NO_DATA) + { + + tars::TarsOutputStream osv; + body.writeTo(osv); + string stemp(osv.getBuffer(), osv.getLength()); + vector vtData; + return this->_t.set(sk, stemp,true,vtData); + } + + //读取到数据了, 解包 + if (ret == TC_HashMap::RT_OK) + { + tars::TarsInputStream is; + is.setBuffer(sv.c_str(), sv.length()); + + PropBody stBody; + stBody.readFrom(is); + if(LOG->IsNeedLog(TarsRollLogger::INFO_LOG)) + { + ostringstream os; + head.displaySimple(os); + os<< " "< mSumib; + + for (size_t i=0; i< stBody.vInfo.size(); i++) + { + mSumib.insert(make_pair(stBody.vInfo[i].policy, stBody.vInfo[i].value)); + } + + for (size_t i=0; i< body.vInfo.size(); i++) + { + string sPolicy = body.vInfo[i].policy; + string inValue = body.vInfo[i].value; + map::iterator it = mSumib.find(sPolicy); + if(it != mSumib.end()) + { + if (sPolicy == "Count") + { + long long count = TC_Common::strto(it->second) + TC_Common::strto(inValue); + it->second = TC_Common::tostr(count); + } + else if (sPolicy == "Sum") + { + long long sum = TC_Common::strto(it->second) + TC_Common::strto(inValue); + it->second = TC_Common::tostr(sum); + } + else if (sPolicy == "Min") + { + long long s = TC_Common::strto(it->second); + long long in = TC_Common::strto(inValue); + long long min = s < in ? s : in; + it->second = TC_Common::tostr(min); + } + else if (sPolicy == "Max") + { + long long s = TC_Common::strto(it->second); + long long in = TC_Common::strto(inValue); + long long max = s > in ? s : in; + it->second = TC_Common::tostr(max); + } + else if (sPolicy == "Distr") + { + vector fields; + vector fieldIn; + fields = TC_Common::sepstr(it->second, ","); + fieldIn= TC_Common::sepstr(inValue, ","); + string tmpValue = ""; + for (size_t k=0; k sTmp = TC_Common::sepstr(fields[k], "|"); + vector inTmp = TC_Common::sepstr(fieldIn[k], "|"); + long long tmp = TC_Common::strto(sTmp[1]) + TC_Common::strto(inTmp[1]); + sTmp[1] = TC_Common::tostr(tmp); + fields[k] = sTmp[0]+ "|" +sTmp[1]; + + if (k==0) + { + tmpValue = fields[k]; + } + else + { + tmpValue = tmpValue + "," + fields[k]; + } + } + it->second = tmpValue; + } + else if(sPolicy == "Avg") + { + //double avg = (TC_Common::strto(sValue) + TC_Common::strto(inValue))/2; + vector sTmp = TC_Common::sepstr(it->second,"="); + vector inTmp = TC_Common::sepstr(inValue,"="); + + //总值求和 + double tmpValueSum = TC_Common::strto(sTmp[0]) + TC_Common::strto(inTmp[0]); + //新版本平均值带有记录数,记录求和 + long tmpCntSum = (2 == inTmp.size()?(TC_Common::strto(inTmp[1])):1) + + (2 == sTmp.size()?(TC_Common::strto(sTmp[1])):1); + + it->second = TC_Common::tostr(tmpValueSum) + "=" + TC_Common::tostr(tmpCntSum); + } + } + else + { + mSumib.insert(make_pair(body.vInfo[i].policy, body.vInfo[i].value)); + } + } + + stBody.vInfo.clear(); + + map::iterator it = mSumib.begin(); + while(it != mSumib.end()) + { + StatPropInfo tempProp; + tempProp.policy = it->first; + tempProp.value = it->second; + + stBody.vInfo.push_back(tempProp); + + ++it; + } + + if(LOG->IsNeedLog(TarsRollLogger::INFO_LOG)) + { + ostringstream os; + head.displaySimple(os); + os<< " "< osv; + stBody.writeTo(osv); + string stemp(osv.getBuffer(), osv.getLength()); + vector vtData; + ret = this->_t.set(sk, stemp,true,vtData); + } + } + return ret; + } +}; + + +extern PropertyHashMap g_hashmap; + + + + + + +#endif + + diff --git a/PropertyServer/PropertyImp.cpp b/PropertyServer/PropertyImp.cpp new file mode 100644 index 00000000..fff1b72b --- /dev/null +++ b/PropertyServer/PropertyImp.cpp @@ -0,0 +1,204 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "PropertyImp.h" +#include "PropertyServer.h" + +/////////////////////////////////////////////////////////// +TC_ThreadMutex PropertyImpThreadData::_mutex; +pthread_key_t PropertyImpThreadData::_key = 0; +size_t PropertyImpThreadData::_no=0; + +/////////////////////////////////////////////////////////// +PropertyImpThreadData::PropertyImpThreadData() +: _threadIndex(0) +{ +} +void PropertyImpThreadData::destructor(void* p) +{ + PropertyImpThreadData * pSptd = (PropertyImpThreadData*)p; + if(pSptd) + { + delete pSptd; + pSptd = NULL; + } +} +PropertyImpThreadData * PropertyImpThreadData::getData() +{ + if(_key == 0) + { + TC_LockT lock(_mutex); + if(_key == 0) + { + int iRet = ::pthread_key_create(&_key, PropertyImpThreadData::destructor); + + if (iRet != 0) + { + TLOGERROR("PropertyImpThreadData pthread_key_create fail:"<< errno << ":" << strerror(errno) << endl); + return NULL; + } + } + } + + PropertyImpThreadData * pSptd = (PropertyImpThreadData*)pthread_getspecific(_key); + + if(!pSptd) + { + TC_LockT lock(_mutex); + + pSptd = new PropertyImpThreadData(); + pSptd->_threadIndex = _no; + ++_no; + + int iRet = pthread_setspecific(_key, (void *)pSptd); + + assert(iRet == 0); + } + return pSptd; +} +/////////////////////////////////////////////////////////// +void PropertyImp::initialize() +{ + +} + +int PropertyImp::reportPropMsg(const map& propMsg, tars::TarsCurrentPtr current ) +{ + TLOGINFO("PropertyImp::reportPropMsg size:" << propMsg.size() << endl); + + handlePropMsg(propMsg, current); + + return 0; +} + +int PropertyImp::handlePropMsg(const map &propMsg, tars::TarsCurrentPtr current) +{ + for ( map::const_iterator it = propMsg.begin(); it != propMsg.end(); it++ ) + { + + const StatPropMsgHead &head = it->first; + const StatPropMsgBody &body = it->second; + + PropHead tHead; + tHead.moduleName = head.moduleName; + tHead.propertyName = head.propertyName; + tHead.setName = head.setName; + tHead.setArea = head.setArea; + tHead.setID = head.setID; + tHead.ip = current->getIp(); + + size_t iIndex = 0; + PropertyImpThreadData * td = PropertyImpThreadData::getData(); + + if(td) + { + iIndex = td->_threadIndex; + } + + dump2file(); + + int iBufferIndex = g_app.getSelectBufferIndex(); + + if(_lastBufferIndex != iBufferIndex) + { + if(_lastBufferIndex != -1) + { + TLOGDEBUG("PropertyImp::handlePropMsg iIndex:" << iIndex << "|iBufferIndex:" << iBufferIndex << "|_lastBufferIndex:" << _lastBufferIndex << endl); + + map > >& mBuffer = g_app.getBuffer(); + map > >::iterator iter = mBuffer.find(_lastBufferIndex); + iter->second[iIndex].first = TNOWMS; + iter->second[iIndex].second = 1; + } + + _lastBufferIndex = iBufferIndex; + } + + string sKey = tHead.moduleName; + sKey += tHead.ip; + + int iHashKey = _hashf(sKey) % g_app.getBuffNum(); + + PropertyHashMap *pHashMap = g_app.getHashMapBuff(iBufferIndex, iHashKey); + + ////////////////////////////////////////////////////////////////////////////////////// + + float rate = (pHashMap->getMapHead()._iUsedChunk) * 1.0/pHashMap->allBlockChunkCount(); + + if(rate >0.9) + { + pHashMap->expand(pHashMap->getMapHead()._iMemSize * 2); + TLOGERROR("PropertyImp::handlePropMsg hashmap expand to " << pHashMap->getMapHead()._iMemSize << endl); + } + + int iRet = pHashMap->add(tHead, body); + if(iRet != TC_HashMap::RT_OK ) + { + TLOGERROR("PropertyImp::handlePropMsg add hashmap recourd iRet:" << iRet << endl); + } + + if(LOG->IsNeedLog(TarsRollLogger::INFO_LOG)) + { + ostringstream os; + os.str(""); + head.displaySimple(os); + body.displaySimple(os); + TLOGINFO("ret|"<getNow(); + time_t tTimeInterv = g_app.getInserInterv() * 60;//second + + static time_t g_tLastDumpTime = 0; + + if(g_tLastDumpTime == 0) + { + g_app.getTimeInfo(g_tLastDumpTime,g_sDate,g_sFlag); + } + + if(tTimeNow - g_tLastDumpTime > tTimeInterv) + { + static TC_ThreadLock g_mutex; + TC_ThreadLock::Lock lock( g_mutex ); + if(tTimeNow - g_tLastDumpTime > tTimeInterv) + { + g_app.getTimeInfo(g_tLastDumpTime,g_sDate,g_sFlag); + + int iSelectBuffer = g_app.getSelectBufferIndex(); + iSelectBuffer = !iSelectBuffer; + + g_app.setSelectBufferIndex(iSelectBuffer); + + TLOGDEBUG("PropertyImp::dump2file select buffer:" << iSelectBuffer << "|TimeInterv:" << tTimeInterv << "|now:" << tTimeNow << "|last:" << g_tLastDumpTime << endl); + FDLOG("PropertyPool") << "propertypool ip:" << ServerConfig::LocalIp << "|PropertyImp::dump2file select buffer:" << iSelectBuffer << "|TimeInterv:" << tTimeInterv << "|now:" << tTimeNow << "|last:" << g_tLastDumpTime << endl; + } + } +} + + + + + diff --git a/PropertyServer/PropertyImp.h b/PropertyServer/PropertyImp.h new file mode 100644 index 00000000..d6a4b172 --- /dev/null +++ b/PropertyServer/PropertyImp.h @@ -0,0 +1,111 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __PROPERTY_IMP_H_ +#define __PROPERTY_IMP_H_ + +#include +#include "util/tc_common.h" +#include "util/tc_thread.h" +#include "util/tc_option.h" +#include "util/tc_hash_fun.h" +#include "jmem/jmem_hashmap.h" +#include "servant/PropertyF.h" +#include "PropertyHashMap.h" + +using namespace tars; + +class PropertyImpThreadData : public TC_ThreadPool::ThreadData +{ +public: + static TC_ThreadMutex _mutex; //全局互斥锁 + static pthread_key_t _key; //线程私有数据key + static size_t _no; + + /** + * 构造函数 + */ + PropertyImpThreadData(); + + /** + * 数据资源释放 + * @param p + */ + static void destructor(void* p); + + /** + * 获取线程数据,没有的话会自动创建 + * @return ServantProxyThreadData* + */ + static PropertyImpThreadData * getData(); + +public: + size_t _threadIndex; +}; + +class PropertyImp : public PropertyF,public TC_ThreadLock +{ +public: + + using hash_functor = std::function; + /** + * + */ + PropertyImp() + : _lastBufferIndex(-1) + , _hashf(tars::hash()) + { + } + + /** + * 析够函数 + */ + ~PropertyImp() { } + + /** + * 初始化 + * + * @return int + */ + virtual void initialize(); + + /** + * 退出 + */ + virtual void destroy() { } + + /** + * 上报性属信息 + * @param statmsg, 上报信息 + * @return int, 返回0表示成功 + */ + virtual int reportPropMsg(const map& propMsg, tars::TarsCurrentPtr current ); + +private: + int handlePropMsg(const map &propMsg, tars::TarsCurrentPtr current); + + void dump2file(); + +private: + + int _lastBufferIndex; + hash_functor _hashf; + +}; + +#endif + + diff --git a/PropertyServer/PropertyReapThread.cpp b/PropertyServer/PropertyReapThread.cpp new file mode 100644 index 00000000..ee2a0b61 --- /dev/null +++ b/PropertyServer/PropertyReapThread.cpp @@ -0,0 +1,454 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "PropertyReapThread.h" +#include "util/tc_config.h" +#include "PropertyServer.h" +#include "PropertyDbManager.h" + +//////////////////////////////////////////////////////////////// +ReapSSDProcThread::ReapSSDProcThread(PropertyReapThread * proc) +: _bTerminate(false) +, _proc(proc) +{ +} + +ReapSSDProcThread::~ReapSSDProcThread() +{ + if(isAlive()) + { + terminate(); + getThreadControl().join(); + } + _queue.clear(); +} + +void ReapSSDProcThread::terminate() +{ + _bTerminate = true; + + _queue.notifyT(); +} + +void ReapSSDProcThread::put(QueueItem data) +{ + if(!_bTerminate) + { + _queue.push_back(data); + } +} + +bool ReapSSDProcThread::pop(QueueItem & data) +{ + return _queue.pop_front(data, 1000); +} + +int ReapSSDProcThread::sendAlarmSMS(const string &sMsg) +{ + string errInfo = " ERROR:" + ServerConfig::LocalIp + "_" + sMsg; + TARS_NOTIFY_ERROR(errInfo); + + return 0; +} + +void ReapSSDProcThread::run() +{ + string sDate1(""); + string sFlag1(""); + string sDate2(""); + string sFlag2(""); + + while (!_bTerminate) + { + try + { + sDate1 = ""; + sFlag1 = ""; + sDate2 = ""; + sFlag2 = ""; + + QueueItem item; + + if(pop(item)) + { + if(item._statmsg != NULL) + { + int64_t iBegin = TNOWMS; + int64_t iEnd = 0; + + PropertyDbManager::getInstance()->insert2MultiDbs(item._index, *item._statmsg, item._date, item._tflag); + + iEnd = TNOWMS; + + TLOGDEBUG("ReapSSDProcThread::run stat ip:" << ServerConfig::LocalIp << "|dbIndex:" << item._index << "|" << PropertyDbManager::getInstance()->getIpAndPort(item._index) + << "|date:" << item._date << "|tflag:" << item._tflag << "|timecost(ms):" << (iEnd - iBegin) << "|iBegin:" << iBegin << "|iEnd:" << iEnd << endl); + + FDLOG("PropertyPool") << "ReapSSDProcThread::run stat ip:" << ServerConfig::LocalIp << "|dbIndex:" << item._index << "|" << PropertyDbManager::getInstance()->getIpAndPort(item._index) + << "|date:" << item._date << "|tflag:" << item._tflag << "|timecost(ms):" << (iEnd - iBegin) << "|iBegin:" << iBegin << "|iEnd:" << iEnd << endl; + + if((iEnd - iBegin)/1000 > g_app.getInserInterv() * 40) + { + FDLOG("PropertyPool") << "propertypool ip:" << ServerConfig::LocalIp << "|ReapSSDProcThread::run timeout 8 minute." << endl; + string sMsg("stat ip:"); + sMsg += ServerConfig::LocalIp; + sMsg += " ReapSSDProcThread::run write db:"; + sMsg += PropertyDbManager::getInstance()->getIpAndPort(item._index); + sMsg += "|timeout "; + sMsg += TC_Common::tostr(g_app.getInserInterv() - 2); + sMsg += " Minute."; + + sendAlarmSMS(sMsg); + } + + delete item._statmsg; + item._statmsg = NULL; + } + else + { + TLOGERROR("ReapSSDProcThread::run item._statmsg == NULL." << endl); + } + } + } + catch(exception& e) + { + TLOGERROR("ReapSSDProcThread::run exception:" << e.what() << endl); + FDLOG("PropertyPool") << "ReapSSDProcThread::run exception:" << e.what() << endl; + } + } +} +////////////////////////////////////////////////////////////// +PropertyReapThread::PropertyReapThread() +: _terminate(false) +, _curWeight(0) +, _lastSq(-1) +{ + TLOGDEBUG("PropertyReapThread begin ok." << endl); +} + +PropertyReapThread::~PropertyReapThread() +{ + if (isAlive()) + { + terminate(); + + getThreadControl().join(); + } +} + +void PropertyReapThread::terminate() +{ + TLOGDEBUG("PropertyReapThread terminate." << endl); + + _terminate = true; + + TC_ThreadLock::Lock lock(*this); + + notifyAll(); +} + +void PropertyReapThread::run() +{ + int iInsertDataNum = PropertyDbManager::getInstance()->getInsertDbThreadNum(); + + for(int i = 0; i < iInsertDataNum; ++i) + { + ReapSSDProcThread *r = new ReapSSDProcThread(this); + + r->start(); + + _runners.push_back(r); + } + + string sDate,sTime; + + int dbNumber = PropertyDbManager::getInstance()->getDbNumber(); + + string sRandOrder; + + uint64_t iTotalNum = 0; + + int iLastIndex = -1; + + TLOGDEBUG("propertypool ip:" << ServerConfig::LocalIp << "|PropertyReapThread::run iInsertDataThread:" << iInsertDataNum << "|dbNumber:" << dbNumber << endl); + FDLOG("PropertyPool") << "propertypool ip:" << ServerConfig::LocalIp << "|PropertyReapThread::run iInsertDataThread:" << iInsertDataNum << "|dbNumber:" << dbNumber << endl; + + while (!_terminate) + { + try + { + //双buffer中一个buffer入库 + int iBufferIndex = !(g_app.getSelectBufferIndex()); + int64_t iInterval = 1000; + if(iBufferIndex != iLastIndex && g_app.getSelectBuffer(iBufferIndex, iInterval)) + { + iLastIndex = iBufferIndex; + + iTotalNum = 0; + + vector vAllPropertyMsg; + for(int iStatIndex = 0; iStatIndex < dbNumber; ++iStatIndex) + { + vAllPropertyMsg.push_back(new PropertyMsg()); + } + + int64_t tBegin = TNOWMS; + + getDataFromBuffer(iBufferIndex, vAllPropertyMsg, iTotalNum); + + int64_t tEnd = TNOWMS; + + TLOGDEBUG("propertypool ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iBufferIndex << "|PropertyReapThread::run getDataFromBuffer timecost(ms):" << (tEnd - tBegin) << endl); + FDLOG("PropertyPool") << "propertypool ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iBufferIndex << "|PropertyReapThread::run getDataFromBuffer timecost(ms):" << (tEnd - tBegin) << endl; + + TLOGDEBUG("propertypool ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iBufferIndex << "|PropertyReapThread::run insert begin _vAllStatMsg.size:" << vAllPropertyMsg.size() << "|record num:" << iTotalNum << endl); + FDLOG("PropertyPool") << "propertypool ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iBufferIndex << "|PropertyReapThread::run insert begin _vAllStatMsg.size:" << vAllPropertyMsg.size() << "|record num:" << iTotalNum << endl; + + if(iTotalNum <= 0) + { + for(int iStatIndex = 0; iStatIndex < dbNumber; ++iStatIndex) + { + delete vAllPropertyMsg[iStatIndex]; + } + + vAllPropertyMsg.clear(); + } + else + { + + string sFile=""; + string sDate=""; + string sFlag=""; + time_t time=0; + g_app.getTimeInfo(time,sDate,sFlag); + + //size_t iSize = vAllStatMsg.size(); + + QueueItem item; + int iInsertThreadIndex = 0; + sRandOrder = g_app.getRandOrder(); + + if (sRandOrder == "") + { + sRandOrder = "0"; + } + + map >& mIpHasDbInfo = PropertyDbManager::getInstance()->getIpHasDbInfo(); + map >::iterator m_iter = mIpHasDbInfo.begin(); + + while(m_iter != mIpHasDbInfo.end()) + { + vector &vDb = m_iter->second; + + for(size_t i = 0; i < vDb.size(); ++i) + { + int k = (i + TC_Common::strto(sRandOrder)) % vDb.size(); + + item._index = vDb[k]; + item._date = sDate; + item._tflag = sFlag; + item._statmsg = vAllPropertyMsg[item._index]; + + iInsertThreadIndex = PropertyDbManager::getInstance()->getDbToIpIndex(vDb[k]); + + assert(iInsertThreadIndex >= 0); + + _runners[iInsertThreadIndex]->put(item); + } + + ++m_iter; + } + + if(_terminate) + { + break; + } + } + + for(int k = 0; k < g_app.getBuffNum(); ++k) + { + PropertyHashMap *pHashMap = g_app.getHashMapBuff(iBufferIndex, k); + pHashMap->clear(); + } + + TLOGDEBUG("propertypool ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iBufferIndex << "|PropertyReapThread::run insert record num:" << iTotalNum << "|tast patch finished." << endl); + FDLOG("PropertyPool") << "propertypool ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iBufferIndex << "|PropertyReapThread::run insert record num:" << iTotalNum << "|tast patch finished." << endl; + } + + } + catch(exception& ex) + { + TLOGERROR("PropertyReapThread::run exception:"<< ex.what() << endl); + } + catch(...) + { + TLOGERROR("PropertyReapThread::run ReapSSDThread unkonw exception catched" << endl); + } + + TC_ThreadLock::Lock lock(*this); + timedWait(REAP_INTERVAL); + } + + TLOGDEBUG("PropertyReapThread run setTerminateFlag true." << endl); + + PropertyDbManager::getInstance()->setTerminateFlag(true); + + for(size_t i = 0; i < _runners.size(); ++i) + { + if(_runners[i]->isAlive()) + { + _runners[i]->terminate(); + + _runners[i]->getThreadControl().join(); + } + } + + for(size_t i = 0; i < _runners.size(); ++i) + { + if(_runners[i]) + { + delete _runners[i]; + _runners[i] = NULL; + } + } + + TLOGDEBUG("PropertyReapThread run terminate." << endl); +} + +int PropertyReapThread::getIndexWithWeighted(int iMaxDb,int iGcd,int iMaxW,const vector& vDbWeight) +{ + while (true){ + + _lastSq = (_lastSq + 1) % iMaxDb; + + if (_lastSq == 0) + { + _curWeight = _curWeight - iGcd; + if (_curWeight <= 0) + { + _curWeight = iMaxW; + if(_curWeight == 0) + { + return 0; + } + } + } + + if (vDbWeight[_lastSq] >= _curWeight) + { + return _lastSq; + } + } +} +void PropertyReapThread::getDataFromBuffer(int iIndex, vector &vAllPropertyMsg, uint64_t &iTotalNum) +{ + TLOGDEBUG("PropertyReapThread::getDataFromBuffer iIndex:" << iIndex << "|begin..." << endl); + + try + { + int iCount = 0,dbSeq=0; + + //获取db个数 + int dbNumber = PropertyDbManager::getInstance()->getDbNumber(); + + vector vDbWeight; + int iGcd = 0,iMaxW = 0; + + PropertyDbManager::getInstance()->getDbWeighted(iGcd,iMaxW,vDbWeight); + + bool bEnable = PropertyDbManager::getInstance()->hasEnableWeighted(); + + for(int k = 0; k < g_app.getBuffNum(); ++k) + { + if(_terminate) + { + break; + } + + PropertyHashMap *pHashMap = g_app.getHashMapBuff(iIndex, k); + + if(pHashMap->size() == 0) + { + continue ; + } + + FDLOG("PropertyPool") << "property ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iIndex << "|PropertyReapThread::getData load hashmap k:" << k << endl; + + PropertyHashMap::lock_iterator it = pHashMap->beginSetTime(); + while ( it != pHashMap->end() ) + { + if(_terminate) + { + break; + } + + PropHead head; + PropBody body; + int ret = it->get( head, body ); + if ( ret < 0 ) + { + ++it; + continue; + } + + if (dbNumber > 0) + { + if(bEnable)//按权重入库 + { + dbSeq = getIndexWithWeighted(dbNumber,iGcd,iMaxW,vDbWeight); + TLOGINFO("PropertyReapThread::getIndexWithWeighted |" << dbSeq << endl); + } + else + { + dbSeq = iCount % dbNumber; + } + + (*(vAllPropertyMsg[dbSeq]))[head] = body; + } + + iCount++; + + ++it; + } + + } + + iTotalNum = iCount; + + TLOGDEBUG("PropertyReapThread::getDataFromBuffer Buffer Index:" << iIndex << "|get total size:" << iCount << endl); + FDLOG("PropertyPool") << "propertypool ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iIndex << "|PropertyReapThread::getData get total size:" << iCount << "|end..." << endl; + } + catch (exception& ex) + { + TLOGERROR("PropertyReapThread::getDataFromBuffer exception:" << ex.what() << endl); + FDLOG("PropertyPool") << "propertypool ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iIndex << "|PropertyReapThread::getData exception:" << ex.what() << endl; + + string sMsg("PropertyReapThread::getDataFromBuffer Buffer Index:"); + sMsg += TC_Common::tostr(iIndex); + sMsg += " exception:"; + sMsg += ex.what(); + sendAlarmSMS(sMsg); + } +} + +int PropertyReapThread::sendAlarmSMS(const string &sMsg) +{ + string errInfo = " ERROR:" + ServerConfig::LocalIp + "_" + sMsg; + TARS_NOTIFY_ERROR(errInfo); + + return 0; +} + + diff --git a/PropertyServer/PropertyReapThread.h b/PropertyServer/PropertyReapThread.h new file mode 100644 index 00000000..c6a75b5c --- /dev/null +++ b/PropertyServer/PropertyReapThread.h @@ -0,0 +1,144 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __REAP_THREAD_H__ +#define __REAP_THREAD_H__ +#include +#include "util/tc_thread.h" +#include "util/tc_mysql.h" +#include "util/tc_config.h" +#include "servant/PropertyF.h" +#include "util/tc_common.h" +#include "servant/TarsLogger.h" +#include "PropertyImp.h" + + +using namespace tars; + +extern TC_Config* g_pconf; + +//////////////////////////////////////// +class QueueItem +{ +public: + size_t _index; + string _date; + string _tflag; + PropertyMsg *_statmsg; + + QueueItem() + : _index(0) + , _date("") + , _tflag("") + , _statmsg(NULL) + {} +}; +//////////////////////////////////////// +class PropertyReapThread; +//////////////////////////////////////// +/** + * 向数据库插入数据的线程类 + */ +class ReapSSDProcThread : public TC_Thread +{ +public: + enum + { + TIME_INTERVAL = 5000//更新业务线程时间 + }; + ReapSSDProcThread(PropertyReapThread * proc); + + ~ReapSSDProcThread(); + + void terminate(); + + virtual void run(); + + void put(QueueItem data); + + bool pop(QueueItem & data); + + int sendAlarmSMS(const string &sMsg); + +private: + bool _bTerminate; + + PropertyReapThread * _proc; + + TC_ThreadQueue _queue; +}; +////////////////////////////////////////////// +/** + * 用于执行定时操作的线程类 + */ +class PropertyReapThread : public TC_Thread, public TC_ThreadLock +{ +public: + /** + * 定义常量 + */ + enum + { + REAP_INTERVAL = 3000, + }; + + /** + * 构造 + */ + PropertyReapThread(); + + /** + * 析够 + */ + ~PropertyReapThread(); + + /** + * 结束线程 + */ + void terminate(); + + /** + * 轮询函数 + */ + virtual void run(); + +private: + /* + * 从buffer中取数据 + */ + void getDataFromBuffer(int iIndex, vector &vAllStatSecMsg, uint64_t &iTotalNum); + + int sendAlarmSMS(const string &sMsg); + + /** + * 通过权重轮询调度算法获取要插入数据的db index + * @param iMaxDb db个数 + * @param iGcd 所有权重的最大公约数 + * @param iMaxW 最大权重值 + * @param vDbWeight 所有db的权重值 + * + * @return int + */ + int getIndexWithWeighted(int iMaxDb,int iGcd,int iMaxW,const vector& vDbWeight); + +private: + bool _terminate; + int _curWeight; + int _lastSq; + vector _runners; +}; + +#endif diff --git a/PropertyServer/PropertyServer.cpp b/PropertyServer/PropertyServer.cpp new file mode 100644 index 00000000..a0ef4779 --- /dev/null +++ b/PropertyServer/PropertyServer.cpp @@ -0,0 +1,307 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "PropertyServer.h" +#include "PropertyImp.h" +#include "servant/AppCache.h" + +void PropertyServer::initialize() +{ + try + { + //关闭远程日志 + TarsTimeLogger::getInstance()->enableRemote("", false); + TarsTimeLogger::getInstance()->enableRemote("PropertyPool", true); + + //增加对象 + addServant( ServerConfig::Application + "." + ServerConfig::ServerName +".PropertyObj" ); + + _insertInterval = TC_Common::strto(g_pconf->get("/tars/hashmap","5")); + if(_insertInterval < 5) + { + _insertInterval = 5; + } + + //获取业务线程个数 + string sAdapter = ServerConfig::Application + "." + ServerConfig::ServerName + ".PropertyObjAdapter"; + string sHandleNum = "/tars/application/server/"; + sHandleNum += sAdapter; + sHandleNum += ""; + + int iHandleNum = TC_Common::strto(g_pconf->get(sHandleNum, "50")); + vector > vec; + vec.resize(iHandleNum); + + initHashMap(); + + string s(""); + _selectBuffer = getSelectBufferFromFlag(s); + + + for(size_t i =0; i < vec.size(); ++i) + { + vec[i].first = 0; + vec[i].second = 0; + } + _buffer[_selectBuffer] = vec; + + + for(size_t i =0; i < vec.size(); ++i) + { + vec[i].first = 0; + vec[i].second = 1; + } + _buffer[!_selectBuffer] = vec; + + TLOGDEBUG("PropertyServer::initialize iHandleNum:" << iHandleNum<< endl); + FDLOG("PropertyPool") << "PropertyServer::initialize iHandleNum:" << iHandleNum << endl; + + + TLOGDEBUG("PropertyServer::initialize iSelectBuffer:" << _selectBuffer<< endl); + FDLOG("PropertyPool") << "PropertyServer::initialize iSelectBuffer:" << _selectBuffer << endl; + + + _randOrder = AppCache::getInstance()->get("RandOrder"); + TLOGDEBUG("PropertyServer::initialize randorder:" << _randOrder << endl); + + _reapThread = new PropertyReapThread(); + + _reapThread->start(); + + TARS_ADD_ADMIN_CMD_PREFIX("tars.tarsproperty.randorder", PropertyServer::cmdSetRandOrder); + } + catch ( exception& ex ) + { + TLOGERROR("PropertyServer::initialize catch exception:" << ex.what() << endl); + exit( 0 ); + } + catch ( ... ) + { + TLOGERROR("PropertyServer::initialize unknow exception catched" << endl); + exit( 0 ); + } +} +string PropertyServer::getRandOrder(void) +{ + return _randOrder; +} + +string PropertyServer::getClonePath(void) +{ + return _clonePath; +} + +int PropertyServer::getInserInterv(void) +{ + return _insertInterval; +} + +bool PropertyServer::getSelectBuffer(int iIndex, int64_t iInterval) +{ + int64_t iNow = TNOWMS; + bool bFlag = true; + vector > &vBuffer = _buffer[iIndex]; + + for(vector >::size_type i=0; i != vBuffer.size(); i++) + { + if(vBuffer[i].second != 1) + { + //TLOGDEBUG("getSelectBuffer return false|i:" << i << "|ret:" << vBuffer[i].second << endl); + return false; + } + } + + for(vector >::size_type i=0; i != vBuffer.size(); i++) + { + if((iNow - vBuffer[i].first) < iInterval) + { + bFlag = false; + } + } + + if(bFlag) + { + for(vector >::size_type i=0; i != vBuffer.size(); i++) + { + vBuffer[i].second = 0; + } + + TLOGDEBUG("PropertyServer::getSelectBuffer getSelectBuffer end return true" << endl); + return true; + } + + TLOGDEBUG("PropertyServer::getSelectBuffer getSelectBuffer end return false" << endl); + return false; +} + +int PropertyServer::getSelectBufferFromFlag(const string& sFlag) +{ + if(sFlag.length()!=0) + { + return (TC_Common::strto(sFlag.substr(2,2))/_insertInterval)%2; + } + else + { + time_t tTime=0; + string sDate="",flag=""; + getTimeInfo(tTime,sDate,flag); + return (TC_Common::strto(flag.substr(2,2))/_insertInterval)%2; + } +} + +bool PropertyServer::cmdSetRandOrder(const string& command, const string& params, string& result) +{ + try + { + TLOGINFO("PropertyServer::cmdSetRandOrder " << command << " " << params << endl); + + _randOrder = params; + + result = "set RandOrder [" + _randOrder + "] ok"; + + AppCache::getInstance()->set("RandOrder",_randOrder); + } + catch (exception &ex) + { + result = ex.what(); + } + return true; +} + +void PropertyServer::initHashMap() +{ + TLOGDEBUG("PropertyServer::initHashMap begin" << endl); + + int iHashMapNum = TC_Common::strto(g_pconf->get("/tars/hashmap","3")); + + TLOGDEBUG("PropertyServer::initHashMap iHashMapNum:" << iHashMapNum << endl); + + _buffNum = iHashMapNum; + + _hashmap = new PropertyHashMap *[2]; + + for(int k = 0; k < 2; ++k) + { + _hashmap[k] = new PropertyHashMap[iHashMapNum](); + } + + int iMinBlock = TC_Common::strto(g_pconf->get("/tars/hashmap","128")); + int iMaxBlock = TC_Common::strto(g_pconf->get("/tars/hashmap","256")); + float iFactor = TC_Common::strto(g_pconf->get("/tars/hashmap","2")); + int iSize = TC_Common::toSize(g_pconf->get("/tars/hashmap"), 1024*1024*256); + + + _clonePath = ServerConfig::DataPath + "/" + g_pconf->get("/tars/hashmap","clone"); + + if(!TC_File::makeDirRecursive(_clonePath)) + { + TLOGERROR("cannot create hashmap file " << _clonePath << endl); + exit(0); + } + + TLOGDEBUG("PropertyServer::initHashMap init multi hashmap begin..." << endl); + + for(int i = 0; i < 2; ++i) + { + for(int k = 0; k < iHashMapNum; ++k) + { + string sFileConf("/tars/hashmapget(sFileConf, sFileDefault); + + string sPath = TC_File::extractFilePath(sHashMapFile); + + if(!TC_File::makeDirRecursive(sPath)) + { + TLOGERROR("cannot create hashmap file " << sPath << endl); + exit(0); + } + + try + { + TLOGINFO("initDataBlockSize size: " << iMinBlock << ", " << iMaxBlock << ", " << iFactor << endl); + + _hashmap[i][k].initDataBlockSize(iMinBlock,iMaxBlock,iFactor); + + if(TC_File::isFileExist(sHashMapFile)) + { + iSize = TC_File::getFileSize(sHashMapFile); + } + _hashmap[i][k].initStore( sHashMapFile.c_str(), iSize ); + + TLOGINFO("\n" << _hashmap[i][k].desc() << endl); + } + catch(TC_HashMap_Exception &e) + { + TC_File::removeFile(sHashMapFile,false); + throw runtime_error(e.what()); + } + + } + } + + TLOGDEBUG("PropertyServer::initHashMap init multi hashmap end..." << endl); +} + +void PropertyServer::destroyApp() +{ + if(_reapThread) + { + delete _reapThread; + _reapThread = NULL; + } + + for(int i = 0; i < 2; ++i) + { + if(_hashmap[i]) + { + delete [] _hashmap[i]; + } + } + + if(_hashmap) + { + delete [] _hashmap; + } + + TLOGDEBUG("PropertyServer::destroyApp ok" << endl); +} + +void PropertyServer::getTimeInfo(time_t &tTime,string &sDate,string &sFlag) +{ + //3G统计要求 + //loadIntev 单位为分钟 + string sTime,sHour,sMinute; + time_t t = TNOW; + t = (t/(_insertInterval*60))*_insertInterval*60; //要求必须为Intev整数倍 + tTime = t; + t = (t%3600 == 0?t-60:t); //要求将9点写作0860 + sTime = TC_Common::tm2str(t,"%Y%m%d%H%M"); + sDate = sTime.substr(0,8); + sHour = sTime.substr(8,2); + sMinute = sTime.substr(10,2); + sFlag = sHour + (sMinute=="59"?"60":sMinute); //要求将9点写作0860 +} + diff --git a/PropertyServer/PropertyServer.h b/PropertyServer/PropertyServer.h new file mode 100644 index 00000000..4cc50efe --- /dev/null +++ b/PropertyServer/PropertyServer.h @@ -0,0 +1,101 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __PROPERTY_SERVER_H_ +#define __PROPERTY_SERVER_H_ + +#include "servant/Application.h" +#include "PropertyReapThread.h" + +using namespace tars; + +class PropertyServer : public Application +{ + +public: + + PropertyServer() + : _reapThread(NULL) + , _hashmap(NULL) + {} + + void getTimeInfo(time_t &tTime,string &sDate,string &sFlag); + + bool cmdSetRandOrder(const string& command, const string& params, string& result); + + string getRandOrder(void); + + string getClonePath(void); + + int getInserInterv(void); + + map > >& getBuffer(){return _buffer;} + + bool getSelectBuffer(int iIndex, int64_t iInterval); + + int getSelectBufferFromFlag(const string& sFlag); + + int getSelectBufferIndex() { return _selectBuffer; } + + void setSelectBufferIndex(int iIndex) { _selectBuffer = iIndex; } + + PropertyHashMap * getHashMapBuff(int iIndex, int iBuffer) { return &(_hashmap[iIndex][iBuffer]); } + + int getBuffNum() { return _buffNum; } + +protected: + /** + * 初始化, 只会进程调用一次 + */ + virtual void initialize(); + + /** + * 析够, 每个进程都会调用一次 + */ + virtual void destroyApp(); + +private: + + void initHashMap(); +private: + + PropertyReapThread* _reapThread; + + // 随机入库开关 + string _randOrder; + + //数据换存目录 + string _clonePath; + + //数据库插入间隔,单位分钟 + int _insertInterval; + + //双buffer机制 + map > > _buffer; + + int _selectBuffer; + + PropertyHashMap **_hashmap; + + int _buffNum; + +}; + +extern PropertyServer g_app; +extern TC_Config* g_pconf; + +#endif + diff --git a/PropertyServer/main.cpp b/PropertyServer/main.cpp new file mode 100644 index 00000000..fb185d3f --- /dev/null +++ b/PropertyServer/main.cpp @@ -0,0 +1,49 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "PropertyServer.h" +#include + +using namespace std; + +TC_Config* g_pconf; + +PropertyServer g_app; + +/** + * @param argc + * @param argv + * + * @return int + */ +int main( int argc, char* argv[] ) +{ + try + { + g_pconf = &g_app.getConfig(); + g_app.main( argc, argv ); + LOG->debug() << "main init succ" << endl; + g_app.waitForShutdown(); + } + catch ( exception& ex ) + { + cout << ex.what() << endl; + } + + return 0; +} + + diff --git a/QueryPropertyServer/CMakeLists.txt b/QueryPropertyServer/CMakeLists.txt new file mode 100644 index 00000000..d13a2b44 --- /dev/null +++ b/QueryPropertyServer/CMakeLists.txt @@ -0,0 +1,9 @@ +set(MODULE "tarsqueryproperty") + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/deploy/${MODULE}/) + +complice_module(${MODULE}) + + + +#FILE(command 'rm -rf ${EXECUTABLE_OUTPUT_PATH}/tarsquerystat') diff --git a/QueryPropertyServer/DbProxy.cpp b/QueryPropertyServer/DbProxy.cpp new file mode 100644 index 00000000..f42260cc --- /dev/null +++ b/QueryPropertyServer/DbProxy.cpp @@ -0,0 +1,902 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "DbProxy.h" +#include + +/////////////////////////////////////////////////////////// +string tFlagInc(const string& stflag); + +string dateInc(const string& sDate); + +void selectLastMinTime(const string& sUid, int iThread , const string& tbname, const TC_DBConf& tcDbInfo, string & ret, QueryParam &queryParam); + +void query(int iThread, const TC_DBConf & conf, map& mSqlPart, map > &result, string &sRes, QueryParam &queryParam,string &sPolicy); + +DbProxy::DbProxy() +{ +} + +DbProxy::~DbProxy() +{ +} + +int DbProxy::createRespHead(const vector &res, const string& sLasttime, string& result, bool bDbCountFlag) +{ + int iRet = 0; + string sRes; + + //检查查询返回值,如果一个线程失败,就返回失败。 + for(size_t i=0; i< res.size(); i++) + { + sRes += res[i] ; + if ( res[i][4] != '0' && iRet == 0) + { + iRet = -1; + } + } + + //int total = bDbCountFlag ? g_app.getDbNumber() : g_app.getDbNumber(); + int total = g_app.getDbNumber(); + result = "Ret:"; + result += TC_Common::tostr(iRet); + result += "\nlasttime:"; + result += sLasttime; + result += "\nActiveDb:"; + result += TC_Common::tostr(res.size()); + result += "\nTotalDb:"; + result += TC_Common::tostr(total); + result += "\n"; + result += sRes; + + return iRet; +} +int DbProxy::createRespData(const string& sUid, const map& mSqlPart, const vector > >& vDataList, const string& sHead, string &result, string& sPolicy) +{ + // 组合多线程结果 + //map first由goupby生成 + //map second 由index生成 + int64_t tStart = TNOWMS; + vector > >::const_iterator dataItr = vDataList.begin(); + map > mStatData; + map >::iterator _it; + + for(size_t i = 0; dataItr != vDataList.end(); dataItr++, i++) + { + TLOGDEBUG(sUid << "sum["<size() << endl); + for(map >::const_iterator it = dataItr->begin(); it != dataItr->end(); it++) + { + _it = mStatData.find(it->first); + if (_it != mStatData.end()) + { + const vector &number1 = it->second; + vector &number2 = _it->second; + // 相同key的值 求和,number1和number1的大小是一样的 + for (size_t j=0; jfirst] = it->second; + } + + } + +// dataItr->clear(); + } + + string groupField(""); + + string sTemp(""); +// int iLineNum = 0; + + for(_it = mStatData.begin(); _it != mStatData.end(); _it++) + { + string sKey = _it->first; + vector &vValue = _it->second; + + if(sPolicy == "Avg") + { + double iResult = 0; + for(size_t i = 0; i < vValue.size(); ++i) + { + iResult += vValue[i]; + } + + TLOGDEBUG(sUid << "iResult:" << iResult << "|size:" << vValue.size() << endl); + + if(vValue.size() == 0) + { + iResult = 0; + } + else + { + iResult = iResult / vValue.size(); + } + + TLOGDEBUG(sUid << "Policy Avg iResult:" << iResult << "|size:" << vValue.size() << endl); + + vValue.clear(); + vValue.push_back(iResult); + } + else if(sPolicy == "Max") + { + double iResult = 0; + for(size_t i = 0; i < vValue.size(); ++i) + { + if(i == 0) + { + iResult = vValue[i]; + } + + if(iResult < vValue[i]) + { + iResult = vValue[i]; + } + } + + TLOGDEBUG(sUid << "Policy Max iResult:" << iResult << "|size:" << vValue.size() << endl); + + vValue.clear(); + vValue.push_back(iResult); + } + else if(sPolicy == "Min") + { + double iResult = 0; + for(size_t i = 0; i < vValue.size(); ++i) + { + if(i == 0) + { + iResult = vValue[i]; + } + + if(iResult > vValue[i]) + { + iResult = vValue[i]; + } + } + + TLOGDEBUG(sUid << "Policy Min iResult:" << iResult << "|size:" << vValue.size() << endl); + + vValue.clear(); + vValue.push_back(iResult); + } + else + { + string::size_type position; + + if((position =sKey.find("Avg")) != string::npos) + { + double iResult = 0; + for(size_t i = 0; i < vValue.size(); ++i) + { + iResult += vValue[i]; + } + + TLOGDEBUG(sUid << "Avg iResult:" << iResult << "|size:" << vValue.size() << endl); + + if(vValue.size() == 0) + { + iResult = 0; + } + else + { + iResult = iResult / vValue.size(); + } + + vValue.clear(); + vValue.push_back(iResult); + } + else if((position =sKey.find("Min")) != string::npos) + { + double iResult = 0; + for(size_t i = 0; i < vValue.size(); ++i) + { + if(i == 0) + { + iResult = vValue[i]; + } + + if(iResult > vValue[i]) + { + iResult = vValue[i]; + } + } + + TLOGDEBUG(sUid << "Min iResult:" << iResult << "|size:" << vValue.size() << endl); + + vValue.clear(); + vValue.push_back(iResult); + } + else if((position =sKey.find("Max")) != string::npos) + { + double iResult = 0; + for(size_t i = 0; i < vValue.size(); ++i) + { + if(i == 0) + { + iResult = vValue[i]; + } + + if(iResult < vValue[i]) + { + iResult = vValue[i]; + } + } + + TLOGDEBUG(sUid << "Max iResult:" << iResult << "|size:" << vValue.size() << endl); + + vValue.clear(); + vValue.push_back(iResult); + } + else + { + double iResult = 0; + for(size_t i = 0; i < vValue.size(); ++i) + { + iResult += vValue[i]; + } + + TLOGDEBUG(sUid << "Sum iResult:" << iResult << "|size:" << vValue.size() << endl); + + vValue.clear(); + vValue.push_back(iResult); + } + } + + } + + + + result += sHead + "linecount:" + TC_Common::tostr(mStatData.size()) + "\n"; + + //把 查询结果转换成一行一行的串 + /* + * input :groupby, f_date, f_tflag + * input : index, succ_count, timeout_count + *all map > + *string =>> f_date, f_tflag + *vector =>> succ_count, timeout_count + */ + _it = mStatData.begin(); + while(_it != mStatData.end()) + { + string valueBuffer = ""; + vector::iterator valueIt = _it->second.begin(); + while(valueIt != _it->second.end()) // value is vector int, need transfer to string; + { + valueBuffer += TC_Common::tostr(*valueIt) + ","; + valueIt++; + } + + result += _it->first + ","; + result += valueBuffer + "\n"; + + _it++; + } + + TLOGDEBUG("result:"<getNowMs(); + + //int64_t tEnd = TNOWMS; + + TLOGDEBUG("DbProxy::createRespData "<< sUid << "createRespData size:"<< result.length() << "|timecost(ms):" << (tEnd-tStart) << endl); + return 0; +} + +/** + * 通过线程池进行并发查询 + */ +void DbProxy::queryData(map &mSqlPart, string &sResult, bool bDbCountFlag) +{ + + try + { + string sUid = mSqlPart.find("uid")->second; + + vector vActive; + + if(bDbCountFlag) + { + vActive = g_app.getActiveDbInfo(); + } + else + { + //vActive = g_app.getActiveDbInfo(); + } + + int iThreads = vActive.size(); + + //int iThreads = bDbCountFlag ? g_app.getDbNumber() : g_app.getDbNumber(); + if(iThreads > 0) + { + vector vPolicy(iThreads); + + vector res(iThreads); + + vector > > vDataList(iThreads); + + _queryParam._run_times = iThreads; + + //TLOGDEBUG("DbProxy::queryData sUid:" << sUid << "all thread query data begin." << endl); + + int64_t tStart = TC_TimeProvider::getInstance()->getNowMs(); + + for(int i=0; i < iThreads; i++) + { + auto fwrapper = std::bind(&query, + i, + std::cref(vActive[i]), + std::ref(mSqlPart), + std::ref(vDataList[i]), + std::ref(res[i]), + std::ref(_queryParam), + std::ref(vPolicy[i])); + + if(bDbCountFlag) + { + g_app.getThreadPoolDb().exec(fwrapper); + } + else + { + //g_app.getThreadPoolDb().exec(fwrapper); + } + } + + //等待线程结束 + TLOGDEBUG("DbProxy::queryData sUid:" << sUid << "wait for all thread query data done." << endl); + + bool rc = true; + int ifail = 0; + while(_queryParam._atomic.get() != _queryParam._run_times) + { + { + TC_ThreadLock::Lock lock(_queryParam._monitor); + rc = _queryParam._monitor.timedWait(6000); + } + + ++ifail; + + if(!rc) + { + if(ifail >= 10) + { + break; + } + } + } + + if(ifail >= 10) + { + TLOGDEBUG("DbProxy::queryData sUid:" << sUid << "wait for all thread query data timeout." << endl); + while(_queryParam._atomic.get() != _queryParam._run_times) + { + { + TC_ThreadLock::Lock lock(_queryParam._monitor); + _queryParam._monitor.timedWait(1000); + } + } + } + + if(_queryParam._atomic.get() == _queryParam._run_times) + rc = true; + /*bool rc = false; + { + TC_ThreadLock::Lock lock(_queryParam._monitor); + rc = _queryParam._monitor.timedWait(60000); + }*/ + + int64_t tEnd = TC_TimeProvider::getInstance()->getNowMs(); + + if(rc) + { + _queryParam._run_times = 0; + _queryParam._run_result = 0; + _queryParam._atomic = 0; + + TLOGDEBUG("DbProxy::queryData sUid:" << sUid << "all thread done return:" << _queryParam._run_result <<"|timecost(ms):" << (tEnd - tStart) << endl); + + // 返回ret code + string sHead; + + string sLasttime = getLastTime(mSqlPart); + + if(createRespHead(res, sLasttime, sHead, bDbCountFlag) != 0) + { + _queryParam._run_times = 0; + _queryParam._run_result = 0; + _queryParam._atomic = 0; + + sResult = sHead; + TLOGERROR("DbProxy::queryData query error:" << sHead << endl); + return; + } + + createRespData(sUid, mSqlPart, vDataList, sHead, sResult,vPolicy[vPolicy.size()-1]); + } + else + { + sResult ="Ret:-1\nquery timeout\n"; + + TLOGDEBUG("DbProxy::queryData sUid:" << sUid << "Ret:-1|query timeout." << endl); + } + } + else + { + sResult ="Ret:-1\nno active db\n"; + } + } + catch (exception &ex) + { + TLOGERROR("DbProxy::queryData exception:" << ex.what() << endl); + sResult ="Ret:-1\n" + string(ex.what()) + "\n"; + } + + _queryParam._run_times = 0; + _queryParam._run_result = 0; + _queryParam._atomic = 0; +} + +void query(int iThread, const TC_DBConf & conf, map& mSqlPart, map > &result, string &sRes, QueryParam &queryParam,string &sPolicy) +{ + string sUid = mSqlPart.find("uid")->second; + + TLOGDEBUG("queryData " << sUid << "thread iIndex:" << iThread << endl); + + int64_t tStart = TNOWMS; + try + { + //dateFrom =>> 20111120 + string dateFrom = mSqlPart["date1"]; + string dateTo = mSqlPart["date2"]; + + //tflagFrom =>> 2360 + string tflagFrom = mSqlPart["tflag1"]; + string tflagTo = mSqlPart["tflag2"]; + + // 输入tflag 条件检查 + if (dateFrom.length() != 8 || dateTo.length() != 8 || tflagFrom.length() != 4 || + tflagTo.length() != 4 || + TC_Common::isdigit(tflagFrom) == false || + TC_Common::isdigit(tflagTo) == false) + { + sRes += "ret:-1|iDb:" + TC_Common::tostr(iThread) + "|wrong tflag:" + tflagFrom + "-" + tflagTo + "\n"; + + TLOGERROR("query sUid:" << sUid << sRes << endl); + + queryParam._run_result = -1; + queryParam._atomic.inc(); + + if(queryParam._atomic.get() == queryParam._run_times) + { + TC_ThreadLock::Lock lock(queryParam._monitor); + queryParam._monitor.notifyAll(); + } + + return ; + } + + //groupCond =>> "where slave_name like 'MTTsh2.BrokerServer' and f_tflag >='0000' and f_tflag <='2360' and f_date = '20111120'" + string whereCond = mSqlPart["whereCond"]; + + string::size_type position; + if((position =whereCond.find("policy")) != string::npos) + { + string temp = whereCond.substr(position); + if((position =whereCond.find("Avg")) != string::npos) + { + sPolicy = "Avg"; + } + else if((position =whereCond.find("Max")) != string::npos) + { + sPolicy = "Max"; + } + else if((position =whereCond.find("Min")) != string::npos) + { + sPolicy = "Min"; + } + else + { + sPolicy = "NULL"; + } + } + + //groupCond =>> "group by f_date, f_tflag" + string groupCond = mSqlPart["groupCond"]; + + //sumField =>> "succ_count, timeout_count"; + string sumField = mSqlPart["sumField"]; + + //groupField =>> "f_date, f_tflag" + string groupField = mSqlPart["groupField"]; + + //selectCond =>> "succ_count, timeout_count, f_date, f_tflag" + string selectCond = sumField +"," + groupField; + + //日期格式20111019 + string::size_type pos = string::npos; + string tmpDate = "f_date"; + if ((pos = selectCond.find(tmpDate, 0)) != string::npos) + { + selectCond.replace(pos, tmpDate.length(), "DATE_FORMAT( f_date, '%Y%m%d') as f_date"); + } + + string sDbName = mSqlPart["dataid"]; + string ignoreKey(""); + + + + vector vGroupField = TC_Common::sepstr(groupField, ", "); + vector vSumField = TC_Common::sepstr(sumField, ", "); + + TC_Mysql tcMysql; + + TC_DBConf tcDbConf = conf; + /*if(bFlag) + { + tcDbConf = g_app.getDbInfo(iThread); + } + else + { + tcDbConf = g_app.getDbInfo(iThread); + }*/ + + tcDbConf._database = sDbName; + + tcMysql.init(tcDbConf); + + string sTbNamePre = tcDbConf._database + "_"; + + string sTbName(""); + string sSql(""); + //select range by f_date and f_tflag + for(string day = dateFrom; day <= dateTo; day = dateInc(day)) + { + for(string tflag = tflagFrom; tflag <= tflagTo && (tflag.substr(0,2) < "24"); tflag = tFlagInc(tflag)) + { + //table name:tars_2012060723 + sTbName = sTbNamePre + day + tflag.substr(0,2); + + sSql = "select " + selectCond + " from " + sTbName + " " + ignoreKey + whereCond + " order by null;"; + + tars::TC_Mysql::MysqlData res = tcMysql.queryRecord(sSql); + + TLOGINFO(sUid << "res.size:" << res.size() << "|sSql:" << sSql << endl); + + // result is key:value pair; + //sKey 由groupby生成 + //value由index生成 + //int64_t t2Start = TNOWMS; + for(size_t iRow = 0; iRow < res.size(); iRow++) + { + string sKey = ""; + for(size_t j = 0; j < vGroupField.size(); j++) + { + sKey += sKey.empty()?"":","; + sKey += res[iRow][vGroupField[j]]; + } + + map >::iterator itResult = result.find(sKey); + if (itResult != result.end()) + { + vector& data = itResult->second; + for (size_t j = 0; j < vSumField.size() && j < data.size(); j++) + { + data.push_back(TC_Common::strto(res[iRow][vSumField[j]]));// 相同key的值 求和 + } + } + else + { + vector& vRes = result[sKey]; + for(size_t j = 0; j < vSumField.size(); j++) + { + vRes.push_back( TC_Common::strto(res[iRow][vSumField[j]]));; + } + } + TLOGINFO("query iDb:" << iThread <<" {"<< sKey << ":" << TC_Common::tostr(result[sKey]) << "}" << endl); + } + + TLOGINFO("query iDb :" << iThread << " day:" << day <<" tflag:" << tflag << endl); + } + } //day + + sRes = "ret:0 iDb:" + TC_Common::tostr(iThread) + "\n"; + + //queryParam._atomic.inc(); + } + catch(TC_Mysql_Exception & ex) + { + sRes = "ret:-1|iDb:" + TC_Common::tostr(iThread) + string("|exception:") + ex.what() + "\n"; + TLOGERROR("query sUid:" << sUid << "query:" << sRes << endl); + + queryParam._run_result = -1; + //queryParam._atomic.inc(); + } + catch(exception & ex) + { + sRes = "ret:-1|iDb:" + TC_Common::tostr(iThread) + string("|exception:") + ex.what() + "\n"; + TLOGERROR("query sUid:" << sUid << "query:" << sRes << endl); + + queryParam._run_result = -1; + //queryParam._atomic.inc(); + } + int64_t tEnd = TNOWMS; + + TLOGDEBUG("query sUid:" << sUid << "exit query iDb:" << iThread <<"|timecost(ms):" << (tEnd - tStart) << "|res:" << sRes << endl); + + queryParam._atomic.inc(); + + if(queryParam._atomic.get() == queryParam._run_times) + { + { + TC_ThreadLock::Lock lock(queryParam._monitor); + queryParam._monitor.notifyAll(); + } + + TLOGDEBUG("query sUid:" << sUid << "notify query finish." << endl); + } + + +} + +/////////////////////////////////////////////////////////////////////////////// +string tFlagInc(const string& stflag) +{ + int h = TC_Common::strto(stflag.substr(0,2)); + int m = TC_Common::strto(stflag.substr(2,2)); + + h += 1; + char buf[5]; + snprintf(buf,sizeof(buf),"%.2d%.2d",h,m); + + return string(buf); +} +/////////////////////////////////////////////////////////////////////////////// +string dateInc(const string& sDate) +{ + string ret("20991231"); // 返回大数 + + try + { + int year = TC_Common::strto(sDate.substr(0, 4)); + int mon = TC_Common::strto(sDate.substr(4, 2)); + int day = TC_Common::strto(sDate.substr(6, 2)); + + struct tm *p = NULL; + time_t timep; + struct tm tt = {0}; + + time(&timep); + p=localtime_r(&timep, &tt); + p->tm_mon = mon -1; + p->tm_mday = day +1; + p->tm_year = year -1900 ; + + timep = mktime(p); + ret = TC_Common::tm2str(timep, "%Y%m%d"); + } + catch(exception & ex) + { + TLOGERROR("DbProxy::dateInc exception:" << ex.what() << endl); + } + return ret; +} +/////////////////////////////////////////////////////////////////////////////// +void selectLastMinTime(const string& sUid, int iThread , const string& tbname, const TC_DBConf& tcDbInfo, string & ret, QueryParam &queryParam) +{ + string sId = sUid; + try + { + TC_Mysql tcMysql; + + //TC_DBConf tcDbConf = tcDbInfo; + + //tcDbConf._database = TC_Common::trimright(tbname, "_"); + //tcDbConf._database = tbname; + string sTbNamePre = tbname + ".t_ecstatus"; + + //TLOGDEBUG("selectLastMinTime database name:" << tcDbConf._database << "|tbname:" << tbname << endl); + + tcMysql.init(tcDbInfo); + + int interval = g_app.getInsertInterval(); + time_t now = TC_TimeProvider::getInstance()->getNow(); + + string sDate,sFlag; + // 排除历史过期数据 + string sTime,sHour,sMinute; + time_t t = (now - interval * 60 * 2); + interval = g_app.getInsertInterval(); + t = (t/(interval*60))*interval*60; //要求必须为loadIntev整数倍 + t = (t%3600 == 0?t-60:t); //要求将9点写作0860 + sTime = TC_Common::tm2str(t,"%Y%m%d%H%M"); + sDate = sTime.substr(0,8); + sHour = sTime.substr(8,2); + sMinute = sTime.substr(10,2); + sFlag = sHour + (sMinute=="59"?"60":sMinute); //要求将9点写作0860 + + string sLast = sDate + " " + sFlag; + + string sSql = "select min(lasttime) as lasttime from "+ sTbNamePre+" where appname like '" +"%' and lasttime > '" + sLast + "'" ; + + tars::TC_Mysql::MysqlData res = tcMysql.queryRecord(sSql); + + if (res.size() > 0) + { + TLOGINFO("selectLastTime" << sId << "sSql:" << sSql << "|lasttime:" << res[0]["lasttime"] << endl); + + ret = res[0]["lasttime"]; + } + else + { + ret = ""; + } + //queryParam._atomic.inc(); + } + catch(TC_Mysql_Exception & ex) + { + TLOGERROR("selectLastTime sUid="<< sId <<"exception:"<< ex.what() << endl); + ret = ""; + queryParam._run_result = -1; + //queryParam._atomic.inc(); + } + catch(exception& e) + { + TLOGERROR("selectLastTime sUid="<< sId <<"exception:"<< e.what() << endl); + ret = ""; + queryParam._run_result = -1; + //queryParam._atomic.inc(); + } + + queryParam._atomic.inc(); + if(queryParam._atomic.get() == queryParam._run_times) + { + TC_ThreadLock::Lock lock(queryParam._monitor); + queryParam._monitor.notifyAll(); + TLOGDEBUG("query sUid:" << sId << "notify checktime finish." << endl); + } +} +/////////////////////////////////////////////////////////////////////////////// +string DbProxy::getLastTime(const map& mSqlPart) +{ + string sUid = mSqlPart.find("uid")->second; + + string min = "99999999999"; // 求最小的,初始使用很大的数据 + //TLOGDEBUG("mSqlPart"<< mSqlPart.find("dataid")->second < vDbInfo = g_app.getAllActiveDbInfo(); + + int iThreads = vDbInfo.size(); + + if(iThreads > 0) + { + vector res(iThreads); + + _queryParam._run_times = iThreads; + + int64_t tStart = TC_TimeProvider::getInstance()->getNowMs(); + + for (int i=0; i< iThreads; i++) + { + const string tbname = mSqlPart.find("dataid")->second; + auto fwrapper = std::bind(&selectLastMinTime, + std::cref(sUid), + i, + std::cref(tbname), + std::cref(vDbInfo[i]), + std::ref(res[i]), + std::ref(_queryParam)); + + g_app.getThreadPoolTimeCheck().exec(fwrapper); + } + + TLOGDEBUG("DbProxy::getLastTime sUid:" << sUid << "wait for getLastTime done." << endl); + + bool rc = true; + int ifail = 0; + while(_queryParam._atomic.get() != _queryParam._run_times) + { + { + TC_ThreadLock::Lock lock(_queryParam._monitor); + rc = _queryParam._monitor.timedWait(300); + } + + ++ifail; + + if(!rc) + { + if(ifail >= 10) + { + break; + } + } + } + + if(ifail >= 10) + { + TLOGDEBUG("DbProxy::getLastTime sUid:" << sUid << "wait for getLastTime timeout." << endl); + while(_queryParam._atomic.get() != _queryParam._run_times) + { + { + TC_ThreadLock::Lock lock(_queryParam._monitor); + _queryParam._monitor.timedWait(1000); + } + } + } + + if(_queryParam._atomic.get() == _queryParam._run_times) + rc = true; + /*bool rc = false; + { + TC_ThreadLock::Lock lock(_queryParam._monitor); + rc = _queryParam._monitor.timedWait(3000); + }*/ + + int64_t tEnd = TC_TimeProvider::getInstance()->getNowMs(); + + + if(rc) + { + TLOGDEBUG("DbProxy::getLastTime sUid:" << sUid << "getLastTime all done|return:" << _queryParam._run_result <<"|timecost(ms):" << (tEnd-tStart) << endl); + + for(int i = 0; i < iThreads; ++i) + { + if(res[i] < min) + { + min = res[i]; + } + } + } + else + { + min = ""; + TLOGDEBUG("DbProxy::getLastTime sUid:" << sUid << "getLastTime timeout." << endl); + } + } + else + { + min = ""; + } + + TLOGDEBUG("DbProxy::getLastTime sUid:" << sUid << "final lasttime:" << min << endl); + } + catch (exception &ex) + { + TLOGERROR("DbProxy::getLastTime exception:" << ex.what() << endl); + min = ""; + } + + _queryParam._run_times = 0; + _queryParam._run_result = 0; + _queryParam._atomic = 0; + + return min; +} + + +string DbProxy::makeResult(int iRet, const string& sRes) +{ + size_t act = g_app.getActiveDbInfo().size(); + int total = g_app.getDbInfo().size(); + string result = "Ret:" + TC_Common::tostr(iRet) + "\n" + + "ActiveDb:" + TC_Common::tostr(act) + "\n" + + "TotalDb:" + TC_Common::tostr(total) + "\n" + + sRes; + return result; +} diff --git a/QueryPropertyServer/DbProxy.h b/QueryPropertyServer/DbProxy.h new file mode 100644 index 00000000..3fa215a1 --- /dev/null +++ b/QueryPropertyServer/DbProxy.h @@ -0,0 +1,58 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __DB_PROXY_H_ +#define __DB_PROXY_H_ + +#include "util/tc_common.h" +#include "util/tc_thread.h" +#include "util/tc_option.h" +#include "util/tc_file.h" +#include "util/tc_mysql.h" +#include "util/tc_config.h" +#include "servant/TarsLogger.h" +#include "QueryServer.h" + +using namespace tars; + +class DbProxy +{ +public: + + DbProxy(); + + ~DbProxy(); + + void queryData(map& mSqlPart, string &sResult, bool bDbCountFlag); + + string getLastTime(const map& mSqlPart); + +private: + + int createRespHead(const vector &res, const string& sLasttime ,string& result, bool bDbCountFlag); + + int createRespData(const string& sUid, const map& mSqlPart, const vector > >& vDataList, const string& sHead, string &result, string& sPolicy); + + string makeResult(int iRet, const string& sRes); + +private: + QueryParam _queryParam; +}; + + +#endif + + diff --git a/QueryPropertyServer/DbThread.cpp b/QueryPropertyServer/DbThread.cpp new file mode 100644 index 00000000..e8cd8958 --- /dev/null +++ b/QueryPropertyServer/DbThread.cpp @@ -0,0 +1,161 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "DbThread.h" +#include "util/tc_config.h" +#include "QueryServer.h" + + +DBThread::DBThread() +: _bTerminate(false) +{ + TLOGDEBUG("DBThread init ok" << endl); +} + +DBThread::~DBThread() +{ + if (isAlive()) + { + terminate(); + + getThreadControl().join(); + } + TLOGDEBUG("DBThread terminate." << endl); +} + +void DBThread::terminate() +{ + _bTerminate = true; + + TC_ThreadLock::Lock lock(*this); + + notifyAll(); +} + +void DBThread::run() +{ + TLOGDEBUG("DBThread::run begin." << endl); + while (!_bTerminate) + { + try + { + tryConnect(); + } + catch ( exception& ex ) + { + TLOGERROR("DBThread::run exception:" << ex.what() << endl); + + } + catch (... ) + { + TLOGERROR("DBThread::run unkonw exception catched" << endl); + } + TC_ThreadLock::Lock lock(*this); + timedWait(REAP_INTERVAL); + } +} + +int DBThread::connect(MYSQL** pstMql,const TC_DBConf& tcConf) +{ + + *pstMql = mysql_init(NULL); + if (mysql_real_connect(*pstMql,tcConf._host.c_str(), tcConf._user.c_str(), tcConf._password.c_str(), tcConf._database.c_str(), tcConf._port, NULL, tcConf._flag) == NULL) + { + TLOGERROR("[TC_Mysql::connect]: mysql_real_connect: " + string(mysql_error(*pstMql)) + ", erron:" < vDbCountInfo = g_app.getDbInfo(); + + size_t iDbCountInfoSize = vDbCountInfo.size(); + + // vector vAtivedbInfo; + + vector vAtivedbCountInfo; + + + + for(size_t i = 0; i < vDbCountInfo.size(); i++) + { + TC_DBConf tcDBConf = vDbCountInfo[i]; + + //tcDBConf._database = "tars_stat"; + + MYSQL* _pstMql = NULL; + + int iRet = connect(&_pstMql,tcDBConf); + + if (_pstMql != NULL) + { + mysql_close(_pstMql); + _pstMql = NULL; + } + + if (iRet != 0) + { + TLOGERROR("DBThread::tryConnect new db host:" << tcDBConf._host << "|port:" << TC_Common::tostr(tcDBConf._port) << "|database:" << tcDBConf._database << endl); + string s("host"); + + s += tcDBConf._host; + s += "|port"; + s += TC_Common::tostr(tcDBConf._port); + s += "|database:"; + s += tcDBConf._database; + + sendAlarmSMS(s); + continue; + } + + vAtivedbCountInfo.push_back(vDbCountInfo[i]);; + } + + size_t iActiveDbCountInfoSize = vAtivedbCountInfo.size(); + + if(iDbCountInfoSize != iActiveDbCountInfoSize) + { + string sMsg = "statcount old db size:"; + sMsg += TC_Common::tostr(iDbCountInfoSize); + sMsg += "|statcount active db size:"; + sMsg += TC_Common::tostr(iActiveDbCountInfoSize); + sMsg += "|no equal."; + + sendAlarmSMS(sMsg); + } + + g_app.setActiveDb(vAtivedbCountInfo); + } + catch (exception& ex) + { + TLOGERROR("DBThread::tryConnect exception:"<< ex.what() << endl); + } +} + + + diff --git a/QueryPropertyServer/DbThread.h b/QueryPropertyServer/DbThread.h new file mode 100644 index 00000000..2fcf4e20 --- /dev/null +++ b/QueryPropertyServer/DbThread.h @@ -0,0 +1,73 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __DB_THREAD_H_ +#define __DB_THREAD_H_ + +#include +#include "util/tc_thread.h" +#include "util/tc_mysql.h" +#include "util/tc_common.h" +#include "servant/TarsLogger.h" + + +using namespace tars; + +/** + * 用于执行定时操作的线程类 + */ +class DBThread : public TC_Thread, public TC_ThreadLock +{ +public: + /** + * 定义常量 + */ + enum + { + REAP_INTERVAL = 30000 + }; + /** + * 构造 + */ + DBThread(); + + /** + * 析够 + */ + ~DBThread(); + + /** + * 结束线程 + */ + void terminate(); + + /** + * 轮询函数 + */ + virtual void run(); + + void tryConnect(); + + int connect(MYSQL **_pstMql,const TC_DBConf& tcConf); + + void sendAlarmSMS(const string &sMsg); + +private: + bool _bTerminate; + +}; + +#endif diff --git a/QueryPropertyServer/QueryDbThread.cpp b/QueryPropertyServer/QueryDbThread.cpp new file mode 100644 index 00000000..6a4a72c5 --- /dev/null +++ b/QueryPropertyServer/QueryDbThread.cpp @@ -0,0 +1,158 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "QueryDbThread.h" +#include "QueryServer.h" +#include "DbProxy.h" + +///////////////////////////////////////////////////////////////////////// +QueryDbThread::QueryDbThread() +: _terminate(false) +{ + TLOGDEBUG("QueryDbThread init ok" << endl); +} + +QueryDbThread::~QueryDbThread() +{ + terminate(); + + TLOGDEBUG("QueryDbThread terminate." << endl); +} + +void QueryDbThread::start(int iThreadNum) +{ + for(int i = 0; i < iThreadNum; ++i) + { + HandleThreadRunner *r = new HandleThreadRunner(this); + + r->start(); + + _runners.push_back(r); + } +} + +void QueryDbThread::terminate() +{ + _terminate = true; + + for (uint32_t i = 0; i < _runners.size(); ++i) + { + if (_runners[i]->isAlive()) + { + _runners[i]->terminate(); + + _queue.notifyT(); + } + } + + for (uint32_t i = 0; i < _runners.size(); ++i) + { + if(_runners[i]->isAlive()) + { + _runners[i]->getThreadControl().join(); + } + } + + _queue.clear(); + + for (uint32_t i = 0; i < _runners.size(); ++i) + { + if(_runners[i]) + { + delete _runners[i]; + _runners[i] = NULL; + } + } +} + +bool QueryDbThread::pop(QueryItem* &pItem) +{ + return _queue.pop_front(pItem, 2000); +} + +void QueryDbThread::put(QueryItem* pItem) +{ + if(!_terminate && pItem) + { + _queue.push_back(pItem); + } +} + +///////////////////////////////////////////////////////////////////////// +HandleThreadRunner::HandleThreadRunner(QueryDbThread* proc) +: _terminate(false) +, _proc(proc) +{ +} + +void HandleThreadRunner::terminate() +{ + _terminate = true; +} + +void HandleThreadRunner::run() +{ + string sRes(""); + DbProxy _dbproxy; + int64_t tStart = 0; + int64_t tEnd = 0; + + while (!_terminate) + { + QueryItem* pQueryItem = NULL; + + if(!_terminate && _proc->pop(pQueryItem)) + { + try + { + tStart = TNOWMS; + + _dbproxy.queryData(pQueryItem->mQuery, sRes, pQueryItem->bFlag); + + tEnd = TNOWMS; + + sRes += "endline\n"; + + pQueryItem->current->sendResponse(sRes.c_str(), sRes.length()); + + FDLOG("inout") << "HandleThreadRunner::run sUid:" << pQueryItem->sUid << "queryData timecost(ms):" << (tEnd - tStart) << endl; + } + catch(exception& ex) + { + TLOGERROR("HandleThreadRunner::run exception:" << ex.what() << endl); + + string sResult = "Ret:-1\n" + string(ex.what()) + "\nendline\n"; + pQueryItem->current->sendResponse(sResult.c_str(), sResult.length()); + + FDLOG("inout") << "HandleThreadRunner::run sUid:" << pQueryItem->sUid << "exception:" << ex.what() << endl; + } + catch(...) + { + TLOGERROR("HandleThreadRunner::run exception." << endl); + + string sResult = "Ret:-1\nunknown exception\nendline\n"; + pQueryItem->current->sendResponse(sResult.c_str(), sResult.length()); + + FDLOG("inout") << "HandleThreadRunner::run sUid:" << pQueryItem->sUid << "unknown exception." << endl; + } + + sRes = ""; + + delete pQueryItem; + pQueryItem = NULL; + } + } +} diff --git a/QueryPropertyServer/QueryDbThread.h b/QueryPropertyServer/QueryDbThread.h new file mode 100644 index 00000000..49496be1 --- /dev/null +++ b/QueryPropertyServer/QueryDbThread.h @@ -0,0 +1,78 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __QUERY_DB_BY_HASH_THREAD_H_ +#define __QUERY_DB_BY_HASH_THREAD_H_ + +#include +#include +#include "util/tc_thread.h" +#include "util/tc_mysql.h" +#include "util/tc_common.h" +#include "util/tc_thread_queue.h" +#include "QueryItem.h" + +using namespace tars; +using namespace std; + +////////////////////////////////////////////////////////////////////////////// +class QueryDbThread; + +////////////////////////////////////////////////////////////////////////////// +class HandleThreadRunner : public TC_Thread +{ +public: + + HandleThreadRunner(QueryDbThread* proc); + + virtual void run(); + + void terminate(); +private: + + bool _terminate; + + QueryDbThread * _proc; + +}; +////////////////////////////////////////////////////////////////////////////// +class QueryDbThread +{ +public: + + QueryDbThread(); + + ~QueryDbThread(); + + void terminate(); + + void start(int iThreadNum); + + void put(QueryItem* pItem); + + bool pop(QueryItem* &pItem); + + size_t getQueueSize() { return _queue.size(); }; + +private: + bool _terminate; + + TC_ThreadQueue _queue; + + vector _runners; +}; + +#endif diff --git a/QueryPropertyServer/QueryImp.cpp b/QueryPropertyServer/QueryImp.cpp new file mode 100644 index 00000000..b53839c0 --- /dev/null +++ b/QueryPropertyServer/QueryImp.cpp @@ -0,0 +1,143 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "QueryImp.h" +#include "RequestDecoder.h" +#include "QueryItem.h" +#include "servant/Application.h" + +using namespace std; + +////////////////////////////////////////////////////// +void QueryImp::initialize() +{ + //initialize servant here: + //... +} + +////////////////////////////////////////////////////// +void QueryImp::destroy() +{ + //destroy servant here: + //... +} + + +int QueryImp::doRequest(tars::TarsCurrentPtr current, vector& response) +{ + const vector& request = current->getRequestBuffer(); + string buf((const char*)(&request[0]), request.size()); + string sUid = TC_Common::tostr(g_app.genUid()) + "|"; + + FDLOG("inout") << "QueryImp::doRequest sUid:" << sUid << "doRequest input:" << buf << endl; + TLOGDEBUG(sUid << "QueryImp::doRequest sUid:" << sUid << "doRequest input:" << buf << endl); + + doQuery(sUid, buf, false, current); + + return 0; +} + +int QueryImp::doQuery(const string sUid, const string &sIn, bool bTarsProtocol, tars::TarsCurrentPtr current) +{ + try + { + size_t pos = sIn.rfind("}"); // find json end + + string s(""); + + if (pos != string::npos) + { + s = sIn.substr(0, pos+1); + } + else + { + throw TC_Exception("bad query string"); + } + + RequestDecoder decoder(s); + TLOGDEBUG("QueryImp::doQuery"<getNowMs(); + + string lasttime = _proxy.getLastTime(decoder.getSql()); + sResult += "lasttime:" + lasttime + "\n"; + sResult += "endline\n"; + + tEnd = TC_TimeProvider::getInstance()->getNowMs(); + + current->sendResponse(sResult.c_str(), sResult.length()); + + FDLOG("inout") << "QueryImp::doQuery time_check sUid:" << sUid << "send result succ,size:"<< sResult.length() << "|timecost(ms):" << (tEnd-tStart) << endl; + TLOGDEBUG("QueryImp::doQuery time_check sUid:" << sUid << "send result succ,size:"<< sResult.length() << "|timecost(ms):" << (tEnd-tStart) << endl); + } + + else if(ret == RequestDecoder::QUERY) + { + current->setResponse(false); + QueryItem * pItem = new QueryItem(); + pItem->sUid = sUid; + pItem->current = current; + pItem->mQuery = decoder.getSql(); + + map &mSqlPart = decoder.getSql(); + + map::iterator it; + for(it=mSqlPart.begin();it!=mSqlPart.end();it++) + { + TLOGDEBUG("QueryImp::mysql "<first<<"|"<second< vGroupField = TC_Common::sepstr(sGroupField, ", "); + + pItem->bFlag = true; + g_app.getThreadPoolQueryDb()->put(pItem); + + TLOGDEBUG("QueryImp::doQuery all dbcount." << endl); + } + else + { + TLOGERROR("QueryImp::doQuery " << sUid << "decode request failed\n" <sendResponse(sResult.c_str(), sResult.length()); + + FDLOG("inout") << "QueryImp::doQuery failed sUid:" << sUid << endl; + } + } + catch(exception &ex) + { + TLOGERROR("QueryImp::doQuery exception:" << ex.what() << endl); + string sResult = "Ret:-1\n" + string(ex.what()) + "\nendline\n"; + current->sendResponse(sResult.c_str(), sResult.length()); + + FDLOG("inout") << "QueryImp::doQuery exception sUid:" << sUid << endl; + } + return 0; +} diff --git a/QueryPropertyServer/QueryImp.h b/QueryPropertyServer/QueryImp.h new file mode 100644 index 00000000..4fb6c53c --- /dev/null +++ b/QueryPropertyServer/QueryImp.h @@ -0,0 +1,63 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef _QueryImp_H_ +#define _QueryImp_H_ + +#include "servant/Application.h" +#include "util/tc_common.h" +#include "util/tc_mysql.h" +#include "util/tc_config.h" +#include "DbProxy.h" + +/** + * + * + */ +class QueryImp : public tars::Servant +{ +public: + /** + * + */ + virtual ~QueryImp() {} + + /** + * + */ + virtual void initialize(); + + /** + * + */ + virtual void destroy(); + + /** + * + */ + + + virtual int doRequest(tars::TarsCurrentPtr current, vector& response); + + +private: + int doQuery(const string sUid, const string &sIn, bool bTarsProtocol, tars::TarsCurrentPtr current); + +private: + DbProxy _proxy; +}; +///////////////////////////////////////////////////// +#endif diff --git a/QueryPropertyServer/QueryItem.h b/QueryPropertyServer/QueryItem.h new file mode 100644 index 00000000..a44d0f68 --- /dev/null +++ b/QueryPropertyServer/QueryItem.h @@ -0,0 +1,43 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __QUERY_ITEM_H_ +#define __QUERY_ITEM_H_ + +#include +#include +#include "servant/Application.h" + +using namespace std; +using namespace tars; + +///////////////////////////////////////////////////////////////////// +class QueryItem +{ +public: + bool bFlag; + string sUid; + map mQuery; + tars::TarsCurrentPtr current; + + QueryItem() + : bFlag(false) + , sUid("") + , current(NULL) + {} +}; + +#endif diff --git a/QueryPropertyServer/QueryServer.cpp b/QueryPropertyServer/QueryServer.cpp new file mode 100644 index 00000000..cafbba70 --- /dev/null +++ b/QueryPropertyServer/QueryServer.cpp @@ -0,0 +1,242 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "QueryServer.h" +#include "QueryImp.h" + +using namespace std; + +QueryServer g_app; + +TC_Config * g_pconf; +///////////////////////////////////////////////////////////////// + +struct JsonProtocol +{ + + static int parse(string &in, string &out) + { + TLOGINFO("JsonProtocol parse:" << in << endl); + + string::size_type jsonEnd = in.find("}"); + + if (jsonEnd != string::npos ) + { + out = in; + in = ""; + return TC_EpollServer::PACKET_FULL; //返回1表示收到的包已经完全 + } + + return TC_EpollServer::PACKET_ERR; //返回-1表示收到包协议错误,框架会自动关闭当前连接 + } +}; + + + +void QueryServer::initialize() +{ + //initialize application here: + //... + vector v_dblist; + vector v_dbcountlist; + + g_pconf->getDomainVector("/tars/countdb", v_dbcountlist); + + size_t iDbNumber = v_dblist.size(); + + size_t iDbCountNumber = v_dbcountlist.size(); + + TLOGDEBUG("QueryServer::initialize stat dbstat size:" << iDbNumber << "|dbcount size:" << iDbCountNumber << endl); + + for(size_t i = 0; i < iDbCountNumber; i++) + { + TC_DBConf tcDBConf; + + string path= "/tars/countdb/" + v_dbcountlist[i]; + + tcDBConf.loadFromMap(g_pconf->getDomainMap(path)); + + _dbStatInfo.push_back(tcDBConf); + } + + _activeDbInfo = _dbStatInfo; + + _dBThread = new DBThread(); + + _dBThread->start(); + + _queryFlag.insert("f_date"); + _queryFlag.insert("f_tflag"); + _queryFlag.insert("master_name"); + _queryFlag.insert("slave_name"); + _queryFlag.insert("slave_ip"); + _queryFlag.insert("interface_name"); + + _insertInterval = TC_Common::strto(g_pconf->get("/tars","5")); + + size_t iDbThreadPoolSize = TC_Common::strto(g_pconf->get("/tars/threadpool","8")); + + size_t iTimeCheckPoolSize = TC_Common::strto(g_pconf->get("/tars/threadpool","8")); + + size_t iQueryDbPoolSize = TC_Common::strto(g_pconf->get("/tars/threadpool","4")); + + _timeCheck.init(iTimeCheckPoolSize); + + _timeCheck.start(); + + _poolDb.init(iDbThreadPoolSize); + + _poolDb.start(); + + _tpoolQueryDb = new QueryDbThread(); + + _tpoolQueryDb->start(iQueryDbPoolSize); + + vector vIpGroup = g_pconf->getDomainKey("/tars/notarsslavename"); + TLOGDEBUG("QueryServer::initialize vIpGroup size:" << vIpGroup.size() << endl); + for (unsigned i = 0; i < vIpGroup.size(); i++) + { + _notTarsSlaveName.insert(vIpGroup[i]); + TLOGDEBUG("QueryServer::initialize i:" << i << "|notarsslavename:" << vIpGroup[i] << endl); + } + addServant(ServerConfig::Application + "." + ServerConfig::ServerName + ".NoTarsObj"); + addServantProtocol(ServerConfig::Application + "." + ServerConfig::ServerName + ".NoTarsObj", &JsonProtocol::parse); +} +///////////////////////////////////////////////////////////////// + +void QueryServer::setActiveDb(const vector &vDbInfo) +{ + TC_LockT lock(*this); + _activeDbInfo = vDbInfo; +} + +vector QueryServer::getAllActiveDbInfo() const +{ + TC_LockT lock(*this); + vector vDbInfo; + for(size_t i = 0; i < _activeDbInfo.size(); ++i) + { + vDbInfo.push_back(_activeDbInfo[i]); + } + + return vDbInfo; +} + +vector QueryServer::getDbInfo() const +{ + TC_LockT lock(*this); + return _dbStatInfo; +} + +vector QueryServer::getActiveDbInfo() const +{ + TC_LockT lock(*this); + return _activeDbInfo; +} + +uint32_t QueryServer::genUid() +{ + TC_LockT lock(*this); + + while (++_uniqId == 0); + + return _uniqId; +} + +string QueryServer::dumpDbInfo(const vector& vDbInfo) const +{ + ostringstream os; + + os <::const_iterator it = _queryFlag.find(sKey); + if(it != _queryFlag.end()) + { + return true; + } + return false; +} + +set& QueryServer::getNotTarsSlaveName() +{ + return _notTarsSlaveName; +} + +///////////////////////////////////////////////////////////////// +void +QueryServer::destroyApp() +{ + //destroy application here: + //... + if(_dBThread) + { + delete _dBThread; + _dBThread = NULL; + } + + if(_tpoolQueryDb) + { + delete _tpoolQueryDb; + _tpoolQueryDb = NULL; + } + + bool b = _poolDb.waitForAllDone(1000); + + TLOGDEBUG("QueryServer::destroyApp waitForAllDone _poolDb return:" << b << "|getJobNum:" << _poolDb.getJobNum() << endl); + + _poolDb.stop(); + + b = _timeCheck.waitForAllDone(1000); + + TLOGDEBUG("QueryServer::destroyApp waitForAllDone _timeCheck return:" << b << "|getJobNum:" << _timeCheck.getJobNum() << endl); + + _timeCheck.stop(); +} +///////////////////////////////////////////////////////////////// +int +main(int argc, char* argv[]) +{ + try + { + g_pconf = & g_app.getConfig(); + g_app.main(argc, argv); + TarsTimeLogger::getInstance()->enableRemote("inout",false); + g_app.waitForShutdown(); + } + catch (std::exception& e) + { + cerr << "std::exception:" << e.what() << std::endl; + } + catch (...) + { + cerr << "unknown exception." << std::endl; + } + return -1; +} +///////////////////////////////////////////////////////////////// diff --git a/QueryPropertyServer/QueryServer.h b/QueryPropertyServer/QueryServer.h new file mode 100644 index 00000000..41da8f26 --- /dev/null +++ b/QueryPropertyServer/QueryServer.h @@ -0,0 +1,124 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef _QueryServer_H_ +#define _QueryServer_H_ + +#include +#include +#include "servant/Application.h" +#include "util/tc_thread_mutex.h" +#include "util/tc_lock.h" +#include "util/tc_thread_pool.h" +#include "util/tc_atomic.h" +#include "DbThread.h" +#include "QueryDbThread.h" + +using namespace std; +using namespace tars; + +///////////////////////////////////////////////////////////////////// +class QueryParam +{ +public: + int _run_times; + int _run_result; + TC_Atomic _atomic; + TC_ThreadLock _monitor; + + QueryParam() + : _run_times(0) + , _run_result(0) + , _atomic(0) + {} +}; +///////////////////////////////////////////////////////////////////// +class QueryServer : public Application , public TC_ThreadMutex +{ +public: + /** + * + **/ + virtual ~QueryServer() {}; + + /** + * + **/ + virtual void initialize(); + + /** + * + **/ + virtual void destroyApp(); + + int getInsertInterval() const { return _insertInterval; }; + + size_t getDbNumber() const { return _dbStatInfo.size(); } + + size_t getActiveDbSize() const { return _activeDbInfo.size(); } + + void setActiveDb( const vector &vDbInfo); + + vector getAllActiveDbInfo() const; + + vector getDbInfo() const; + + vector getActiveDbInfo() const; + + TC_DBConf getDbInfo(int iIndex) { return _dbStatInfo[iIndex]; } + + string dumpDbInfo(const vector& vDbInfo) const; + + uint32_t genUid(); + + TC_ThreadPool & getThreadPoolTimeCheck() { return _timeCheck; } + + TC_ThreadPool & getThreadPoolDb() { return _poolDb; } + + QueryDbThread * getThreadPoolQueryDb() { return _tpoolQueryDb; } + + bool searchQueryFlag(const string &sKey); + + //匹配非tars被调服务名 + set& getNotTarsSlaveName(); + +private: + uint32_t _uniqId; //唯一id + + int _insertInterval; //查询最后入库时间使用,入库耗时不会超过入库间隔,单位为分钟 + + DBThread * _dBThread; //定时检查数据库实例是否存活 + + QueryDbThread *_tpoolQueryDb; //用于处理数据库的查询操作 + + vector _dbStatInfo; //数据库信息 + + vector _activeDbInfo; //存活的数据库信息 + + set _queryFlag; //数据库字段 + + TC_ThreadPool _timeCheck; //处理timecheck操作的线程池 + + TC_ThreadPool _poolDb; //具体查询压缩维度后的数据库实例数据的线程池 + + + set _notTarsSlaveName; //匹配非tars被调服务名 +}; + +extern QueryServer g_app; +extern TC_Config * g_pconf; +//////////////////////////////////////////// +#endif diff --git a/QueryPropertyServer/RequestDecoder.cpp b/QueryPropertyServer/RequestDecoder.cpp new file mode 100644 index 00000000..8fd5b390 --- /dev/null +++ b/QueryPropertyServer/RequestDecoder.cpp @@ -0,0 +1,502 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "DbProxy.h" +#include "util/tc_config.h" +#include "QueryServer.h" +#include "RequestDecoder.h" + +static string skey = ""; + + + +RequestDecoder::RequestDecoder(const string& input) +: _input(input) +, _slaveName("") +{ +} +RequestDecoder::~RequestDecoder() +{ + +} + +int RequestDecoder::generateVector(Document &d ,const string s,std::vector &v) +{ + + Value::ConstMemberIterator iter = d.FindMember(s.c_str()); + int i=0; + if (iter == d.MemberEnd()) + { + return 0; + } + else + { + if(iter->value.IsArray()) + { + for (Value::ConstValueIterator itr = iter->value.Begin(); itr != iter->value.End(); ++itr) + { + v.push_back(itr->GetString()); + ++i; + } + } + + else if (iter->value.IsString()) + { + v.push_back(iter->value.GetString()); + i=1; + } + + else + { + return 0; + } + + return i; + } + +} +int RequestDecoder::composeSqlPartition() +{ + vector vConditions; + int iRet=0; + + iRet=generateVector(_req,"filter",vConditions); + + if(iRet==0) + { + return -1; + } + + + string date1,date2; + + int ret = find_field(vConditions, "f_date", date1); + date1 = TC_Common::trim(date1, " ''"); + date1 = TC_Common::trim(date1, " "); + if (ret == EQ || ret ==-1) + { + + date2 = date1; + } + else //NOT EQ, find again + { + ret = find_field(vConditions, "f_date", date2); + date2 = TC_Common::trim(date2, " ''"); + date2 = TC_Common::trim(date2, " "); + if (date1 < date2) + { + + } + else + { + date1.swap(date2); + } + } + + _sql["date1"] = date1; + _sql["date2"] = date2; + //get date end + + //get hour + string tflag1,tflag2; + ret = find_field(vConditions, "f_tflag", tflag1); + tflag1 = TC_Common::trim(tflag1, " \"'"); + if (ret == EQ || ret == -1) + { + + tflag2 = tflag1; + } + else //NOT EQ, find again + { + ret = find_field(vConditions, "f_tflag", tflag2); + tflag2 = TC_Common::trim(tflag2, " \"'"); + if (tflag1 < tflag2) + { + + } + else + { + tflag1.swap(tflag2); + } + } + + _sql["tflag1"] = tflag1; + _sql["tflag2"] = tflag2; + //get hour end + + iRet=generateVector(_req,"filter",vConditions); + if (!vConditions.empty()) + { + string whereCond = ""; + vector::iterator it = vConditions.begin(); + while(it != vConditions.end()) + { + string &sTmp = *it; + string::size_type pos = sTmp.find("slave_name"); + if(pos != string::npos) + { + _slaveName = *it; + } + + whereCond += (whereCond.empty()?"":" and ") + *it ; + it++; + } + + string sWhere(""); + string::size_type ipos = whereCond.find("and istars="); + + if(ipos != string::npos) + { + + string spre = whereCond.substr(0, ipos); + + string snext = whereCond.substr(ipos+9); + + string::size_type ipos1 = snext.find("and"); + + if(ipos1 != string::npos) + { + string s = snext.substr(ipos1); + sWhere = spre; + sWhere += s; + + string sistars = whereCond.substr(ipos+4, (ipos + 9) + ipos1 - (ipos + 4)); + + string value(""); + + int flag = parseCondition(sistars, value); + + TLOGDEBUG("RequestDecoder::composeSqlPartition istars set|sistars:" << sistars << "|flag:" << flag << "|ipos:" << ipos << "|ipos1:" << ipos1 << "|snext:" << snext << endl); + + if(flag == EQ) + { + value = TC_Common::trim(value, " \"'"); + _sql["istars"] = value; + } + else if(flag == NE) + { + value = TC_Common::trim(value, " \"'"); + int iFlag = TC_Common::strto(value); + iFlag = !iFlag; + value = TC_Common::tostr(iFlag); + _sql["istars"] = value; + } + } + else + { + sWhere = spre; + + string sistars = whereCond.substr(ipos+4); + + string value(""); + + int flag = parseCondition(sistars, value); + + if(flag == EQ) + { + value = TC_Common::trim(value, " \"'"); + _sql["istars"] = value; + } + else if(flag == NE) + { + value = TC_Common::trim(value, " \"'"); + int iFlag = TC_Common::strto(value); + iFlag = !iFlag; + value = TC_Common::tostr(iFlag); + _sql["istars"] = value; + } + } + } + else + { + sWhere = whereCond; + } + + _sql["whereCond"] = " where " + sWhere; + + + } + + if(_slaveName != "") + { + string::size_type pos1 = _slaveName.find("'"); + if(pos1 != string::npos) + { + string::size_type pos2 = _slaveName.rfind("'"); + if(pos2 != pos1 && pos2 != string::npos) + { + _slaveName = _slaveName.substr(pos1, (pos2 - pos1 -1)); + } + } + } + + + + vConditions.clear(); + iRet=generateVector(_req,"groupby",vConditions); + + if (!vConditions.empty()) + { + string groupCond = ""; + string groupField = ""; + vector::iterator it = vConditions.begin(); + while(it != vConditions.end()) + { + groupCond += (groupCond.empty()?"":", ") + *it; + groupField += (groupField.empty()?"":", ") + *it; + it++; + } + _sql["groupCond"] = " group by " + groupCond; + _sql["groupField"] = groupField; + } + + string sumField = ""; + vConditions.clear(); + iRet=generateVector(_req,"indexs",vConditions); + if (vConditions.empty()) + { + sumField = " sum(succ_count) "; + } + else + { + vector::iterator it = vConditions.begin(); + while(it != vConditions.end()) + { + // sumField += string((sumField.empty()?"":", ")) + " sum(" + *it + ")" ; + sumField += string((sumField.empty()?"":", ")) + " " + *it + "" ; + it++; + } + } + + _sql["sumField"]= sumField; + return 0; +} + +int RequestDecoder::parseCondition(const string& sCond, string& value) +{ + string::size_type pos =0; + pos= sCond.find(">="); + if (pos != string::npos ) + { + value = sCond.substr(pos+2); + return GE; + } + + pos = sCond.find("<="); + if (pos != string::npos ) + { + value = sCond.substr(pos+2); + return LE; + } + + pos = sCond.find("!="); + if (pos != string::npos ) + { + value = sCond.substr(pos+2); + return NE; + } + pos = sCond.find("<"); + if (pos != string::npos ) + { + value = sCond.substr(pos+1); + return LT; + } + + pos = sCond.find(">"); + if (pos != string::npos ) + { + value = sCond.substr(pos+1); + return GT; + } + + pos = sCond.find("="); + if (pos != string::npos ) + { + value = sCond.substr(pos+1); + return EQ; + } + return 0; +} + +int RequestDecoder::find_field(vector& vCond, const string& field /*f_tflag, f_date*/, string& value ) +{ + vector::iterator it = vCond.begin(); + while(it != vCond.end()){ + + string::size_type pos = it->find(field); + + if(pos != string::npos) + { + string temp = *it; + vCond.erase(it); + return parseCondition(temp, value); + } + it++; + } + return -1; +} + +/* +name : indexs, filter, groupby +*/ +int RequestDecoder::decodeDataid() +{ + + string::size_type pos = _input.find("dataid"); + if (pos == string::npos) + { + return -1; + } + string::size_type endpos = _input.find(",", pos); + _sql["dataid"] = _input.substr(pos + 9, endpos - pos -10); + LOG->debug() << "decodeDataid: " << _sql["dataid"] <debug() << "decodeMethod: " << _sql["method"] < &vFields) +{ + + string::size_type pos1 = arr.find_first_of("["); + if(pos1 == string::npos) + { + LOG->debug() << ("paramh '" + arr + "' is invalid!" ); + return -1; + } + string::size_type pos2 = arr.find_first_of("]"); + if(pos2 == string::npos) + { + LOG->debug() << ("paramh '" + arr + "' is invalid!" ); + return -1; + } + vFields = TC_Common::sepstr(arr.substr(pos1, pos2 -pos1-1), ","); + vector::iterator it = vFields.begin(); + while(it != vFields.end()) + { + + LOG->debug() << "indexs bt " << *it << endl; + string s = TC_Common::trim(*it, "[]\"\""); + *it = s; + LOG->debug() << "indexs at " << *it << endl; + it++; + } + return 0; + + +} + + +map& RequestDecoder::getSql() +{ + return _sql; +} + + +int RequestDecoder::decode() +{ + + _req.Parse(_input.c_str()); + if (_req.HasParseError()) { + TLOGERROR("Decode error:"<<_req.GetParseError()<<"|"<<_input); + return -1; + } + + try + { + vector vConditions ; + generateVector(_req,"method",vConditions); + if(vConditions.size()) + { + _sql["method"] =vConditions[0]; + TLOGDEBUG("Decode"<<_sql["method"]<error() << "RequestDecoder::decode exception:"<< ex.what() << endl; + return -1; + } + return -1; +} + +//传入sUid,供打印使用 +int RequestDecoder::addUid(const string& sUid) +{ + _sql["uid"] = sUid; + return 0; +} + +string RequestDecoder::getLine(const char** ppChar) +{ + string sTmp; + + sTmp.reserve(512); + + while((**ppChar) != '\r' && (**ppChar) != '\n' && (**ppChar) != '\0') + { + sTmp.append(1, (**ppChar)); + (*ppChar)++; + } + + if((**ppChar) == '\r') + { + (*ppChar)++; /* pass the char '\n' */ + } + + (*ppChar)++; + + return sTmp; +} + diff --git a/QueryPropertyServer/RequestDecoder.h b/QueryPropertyServer/RequestDecoder.h new file mode 100644 index 00000000..5d304b19 --- /dev/null +++ b/QueryPropertyServer/RequestDecoder.h @@ -0,0 +1,100 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __REQUEST_DECODE_H__ +#define __REQUEST_DECODE_H__ +#include +#include "util/tc_thread.h" +#include "util/tc_mysql.h" +#include "servant/StatF.h" +#include "util/tc_common.h" +#include "servant/TarsLogger.h" +#include "util/tc_thread.h" +#include "rapidjson/document.h" +#include "rapidjson/writer.h" +#include "rapidjson/stringbuffer.h" + +using namespace rapidjson; + +class RequestDecoder +{ +public: + static string getLine(const char** ppChar); +public: + enum Op + { + SET, + ADD, + SUB, + EQ, + NE, + GT, + LT, + LE, + GE, + LIMIT, + }; + + enum METHOD + { + QUERY = 0, + TIMECHECK, + }; + RequestDecoder(const string& input); + + ~RequestDecoder(); + + int parseCondition(const string& sCond, string& value); + + /** + * 从vCond中解析出field对应的值 + * + */ + int find_field(vector& vCond, const string& field /*f_tflag, f_date*/, string& value ); + + int decode(); + + int decodeDataid(); + + int decodeMethod(); + + int decodeArray(const string& arr, vector &vFields); + + int addUid(const string& sUid); + + map& getSql(); + + int composeSqlPartition(); + + string getQuerySlaveName() { return _slaveName; } + + int generateVector(Document &d ,const string s,std::vector &v); + +private: + //待解析的json请求串 + string _input; + + //解析json得到的数据库查询slave_name + string _slaveName; + + //解析json请求串得到的Dom 文件 + Document _req; + + //解析json得到的数据库查询条件值 + map _sql; +}; +#endif + diff --git a/QueryStatServer/CMakeLists.txt b/QueryStatServer/CMakeLists.txt new file mode 100644 index 00000000..a8e93970 --- /dev/null +++ b/QueryStatServer/CMakeLists.txt @@ -0,0 +1,9 @@ +set(MODULE "tarsquerystat") + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/deploy/${MODULE}/) + +complice_module(${MODULE}) + + + +#FILE(command 'rm -rf ${EXECUTABLE_OUTPUT_PATH}/tarsquerystat') diff --git a/QueryStatServer/DbProxy.cpp b/QueryStatServer/DbProxy.cpp new file mode 100644 index 00000000..b650ba25 --- /dev/null +++ b/QueryStatServer/DbProxy.cpp @@ -0,0 +1,818 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "DbProxy.h" +#include + +/////////////////////////////////////////////////////////// +string tFlagInc(const string& stflag); + +string dateInc(const string& sDate); + +void selectLastMinTime(const string& sUid, int iThread , const string& tbname, const TC_DBConf& tcDbInfo, string & ret, QueryParam &queryParam); + +void query(int iThread, const TC_DBConf & conf, map& mSqlPart, map > &result, string &sRes, QueryParam &queryParam); + +DbProxy::DbProxy() +{ +} + +DbProxy::~DbProxy() +{ +} + +int DbProxy::createRespHead(const vector &res, const string& sLasttime, string& result, bool bDbCountFlag) +{ + int iRet = 0; + string sRes; + + //检查查询返回值,如果一个线程失败,就返回失败。 + for(size_t i=0; i< res.size(); i++) + { + sRes += res[i] ; + if ( res[i][4] != '0' && iRet == 0) + { + iRet = -1; + } + } + + //int total = bDbCountFlag ? g_app.getDbNumber() : g_app.getDbNumber(); + int total = g_app.getDbNumber(); + result = "Ret:"; + result += TC_Common::tostr(iRet); + result += "\nlasttime:"; + result += sLasttime; + result += "\nActiveDb:"; + result += TC_Common::tostr(res.size()); + result += "\nTotalDb:"; + result += TC_Common::tostr(total); + result += "\n"; + result += sRes; + + return iRet; +} +int DbProxy::createRespData(const string& sUid, const map& mSqlPart, const vector > >& vDataList, const string& sHead, string &result) +{ + // 组合多线程结果 + //map first由goupby生成 + //map second 由index生成 + int64_t tStart = TNOWMS; + vector > >::const_iterator dataItr = vDataList.begin(); + map > mStatData; + map >::iterator _it; + + for(size_t i = 0; dataItr != vDataList.end(); dataItr++, i++) + { + TLOGINFO(sUid << "sum["<size() << endl); + for(map >::const_iterator it = dataItr->begin(); it != dataItr->end(); it++) + { + _it = mStatData.find(it->first); + if (_it != mStatData.end()) + { + const vector &number1 = it->second; + vector &number2 = _it->second; + // 相同key的值 求和,number1和number1的大小是一样的 + for (size_t j=0; jfirst] = it->second; + } + } + } + + int iIndex = -1; + size_t iGroupFieldSize = 0; + bool bTars = false; + string sIsTars(""); + string groupField(""); + + map::const_iterator const_it = mSqlPart.find("istars"); + if(const_it != mSqlPart.end()) + { + TLOGDEBUG("DbProxy::createRespData istars:" << const_it->second << endl); + + bTars = true; + + sIsTars = const_it->second; + + map::const_iterator const_it_inner = mSqlPart.find("groupField"); + if(const_it_inner != mSqlPart.end()) + { + groupField = const_it_inner->second; + + vector vGroupField = TC_Common::sepstr(groupField, ", "); + + iGroupFieldSize = vGroupField.size(); + + for(size_t i = 0; i < vGroupField.size(); ++i) + { + if(vGroupField[i] == "slave_name") + { + iIndex = i; + break; + } + } + } + + if(iIndex < 0) + { + bTars = false; + } + } + /*else + { + TLOGDEBUG("DbProxy::createRespData no set istars." << endl); + }*/ + + string sTemp(""); + int iLineNum = 0; + + //把 查询结果转换成一行一行的串 + /* + * input :groupby, f_date, f_tflag + * input : index, succ_count, timeout_count + * all map > + * string =>> f_date, f_tflag + * vector =>> succ_count, timeout_count + */ + _it = mStatData.begin(); + while(_it != mStatData.end()) + { + bool bFilter = false; + if(bTars) + { + vector vGroupField = TC_Common::sepstr(_it->first, ",", true); + + if(sIsTars == "1") + { + set::iterator it; + it = g_app.getNotTarsSlaveName().find(vGroupField[iIndex]); + if(it != g_app.getNotTarsSlaveName().end()) + { + bFilter = true; + } + } + else + { + if(vGroupField.size() != iGroupFieldSize) + { + TLOGERROR("DbProxy::createRespData vGroupField.size:" << vGroupField.size() << "|iGroupFieldSize:" << iGroupFieldSize << "|key:" << _it->first << "|keyFiled:" << groupField << endl); + } + else if(vGroupField[iIndex] == "" || vGroupField[iIndex].size() == 0) + { + TLOGERROR("DbProxy::createRespData iIndex:" << iIndex << "|vGroupField[iIndex]:" << vGroupField[iIndex] << endl); + } + + set::iterator it; + it = g_app.getNotTarsSlaveName().find(vGroupField[iIndex]); + if(it == g_app.getNotTarsSlaveName().end()) + { + bFilter = true; + } + } + + if(!bFilter) + { + ++iLineNum; + + string valueBuffer = ""; + vector::iterator valueIt = _it->second.begin(); + while(valueIt != _it->second.end()) // value is vector int, need transfer to string; + { + valueBuffer += TC_Common::tostr(*valueIt); + valueBuffer += ","; + valueIt++; + } + + sTemp += _it->first; + sTemp += ","; + sTemp += valueBuffer; + sTemp += "\n"; + } + } + else + { + ++iLineNum; + + string valueBuffer = ""; + vector::iterator valueIt = _it->second.begin(); + while(valueIt != _it->second.end()) // value is vector int, need transfer to string; + { + valueBuffer += TC_Common::tostr(*valueIt); + valueBuffer += ","; + valueIt++; + } + + sTemp += _it->first; + sTemp += ","; + sTemp += valueBuffer; + sTemp += "\n"; + } + + _it++; + } + + result += sHead; + result += "linecount:"; + result += TC_Common::tostr(iLineNum); + result += "\n"; + result += sTemp; + + TLOGINFO("DbProxy::createRespData result:"< &mSqlPart, string &sResult, bool bDbCountFlag) +{ + try + { + string sUid = mSqlPart.find("uid")->second; + + vector vActive; + + if(bDbCountFlag) + { + vActive = g_app.getActiveDbInfo(); + } + else + { + //vActive = g_app.getActiveDbInfo(); + } + + int iThreads = vActive.size(); + + if(iThreads > 0) + { + vector res(iThreads); + + vector > > vDataList(iThreads); + + _queryParam._run_times = iThreads; + + //TLOGDEBUG("DbProxy::queryData sUid:" << sUid << "all thread query data begin." << endl); + + int64_t tStart = TC_TimeProvider::getInstance()->getNowMs(); + + for(int i=0; i < iThreads; i++) + { + auto fwrapper = std::bind(&query, + i, + std::cref(vActive[i]), + std::ref(mSqlPart), + std::ref(vDataList[i]), + std::ref(res[i]), + std::ref(_queryParam)); + + if(bDbCountFlag) + { + g_app.getThreadPoolDb().exec(fwrapper); + } + else + { + //g_app.getThreadPoolDb().exec(fwrapper); + } + } + + //等待线程结束 + TLOGDEBUG("DbProxy::queryData sUid:" << sUid << "wait for all thread query data done." << endl); + + bool rc = true; + int ifail = 0; + while(_queryParam._atomic.get() != _queryParam._run_times) + { + { + TC_ThreadLock::Lock lock(_queryParam._monitor); + rc = _queryParam._monitor.timedWait(6000); + } + + ++ifail; + + if(!rc) + { + if(ifail >= 10) + { + break; + } + } + } + + if(ifail >= 10) + { + TLOGDEBUG("DbProxy::queryData sUid:" << sUid << "wait for all thread query data timeout." << endl); + while(_queryParam._atomic.get() != _queryParam._run_times) + { + { + TC_ThreadLock::Lock lock(_queryParam._monitor); + _queryParam._monitor.timedWait(1000); + } + } + } + + if(_queryParam._atomic.get() == _queryParam._run_times) + rc = true; + /*bool rc = false; + { + TC_ThreadLock::Lock lock(_queryParam._monitor); + rc = _queryParam._monitor.timedWait(60000); + }*/ + + int64_t tEnd = TC_TimeProvider::getInstance()->getNowMs(); + + if(rc) + { + _queryParam._run_times = 0; + _queryParam._run_result = 0; + _queryParam._atomic = 0; + + TLOGDEBUG("DbProxy::queryData sUid:" << sUid << "all thread done return:" << _queryParam._run_result <<"|timecost(ms):" << (tEnd - tStart) << endl); + + // 返回ret code + string sHead; + + string sLasttime = getLastTime(mSqlPart); + + if(createRespHead(res, sLasttime, sHead, bDbCountFlag) != 0) + { + _queryParam._run_times = 0; + _queryParam._run_result = 0; + _queryParam._atomic = 0; + + sResult = sHead; + TLOGERROR("DbProxy::queryData query error:" << sHead << endl); + return; + } + + createRespData(sUid, mSqlPart, vDataList, sHead, sResult); + } + else + { + sResult ="Ret:-1\nquery timeout\n"; + + TLOGDEBUG("DbProxy::queryData sUid:" << sUid << "Ret:-1|query timeout." << endl); + } + } + else + { + sResult ="Ret:-1\nno active db\n"; + } + } + catch (exception &ex) + { + TLOGERROR("DbProxy::queryData exception:" << ex.what() << endl); + sResult ="Ret:-1\n" + string(ex.what()) + "\n"; + } + + _queryParam._run_times = 0; + _queryParam._run_result = 0; + _queryParam._atomic = 0; +} + +void query(int iThread, const TC_DBConf & conf, map& mSqlPart, map > &result, string &sRes, QueryParam &queryParam) +{ + string sUid = mSqlPart.find("uid")->second; + + TLOGDEBUG("queryData " << sUid << "thread iIndex:" << iThread << endl); + + int64_t tStart = TNOWMS; + try + { + //dateFrom =>> 20111120 + string dateFrom = mSqlPart["date1"]; + string dateTo = mSqlPart["date2"]; + + //tflagFrom =>> 2360 + string tflagFrom = mSqlPart["tflag1"]; + string tflagTo = mSqlPart["tflag2"]; + + // 输入tflag 条件检查 + if (dateFrom.length() != 8 || dateTo.length() != 8 || tflagFrom.length() != 4 || + tflagTo.length() != 4 || + TC_Common::isdigit(tflagFrom) == false || + TC_Common::isdigit(tflagTo) == false) + { + sRes += "ret:-1|iDb:" + TC_Common::tostr(iThread) + "|wrong tflag:" + tflagFrom + "-" + tflagTo + "\n"; + + TLOGERROR("query sUid:" << sUid << sRes << endl); + + queryParam._run_result = -1; + queryParam._atomic.inc(); + + if(queryParam._atomic.get() == queryParam._run_times) + { + TC_ThreadLock::Lock lock(queryParam._monitor); + queryParam._monitor.notifyAll(); + } + + return ; + } + + //groupCond =>> "where slave_name like 'MTTsh2.BrokerServer' and f_tflag >='0000' and f_tflag <='2360' and f_date = '20111120'" + string whereCond = mSqlPart["whereCond"]; + + //groupCond =>> "group by f_date, f_tflag" + string groupCond = mSqlPart["groupCond"]; + + //sumField =>> "succ_count, timeout_count"; + string sumField = mSqlPart["sumField"]; + + //groupField =>> "f_date, f_tflag" + string groupField = mSqlPart["groupField"]; + + //selectCond =>> "succ_count, timeout_count, f_date, f_tflag" + string selectCond = sumField +"," + groupField; + + //日期格式20111019 + string::size_type pos = string::npos; + string tmpDate = "f_date"; + if ((pos = selectCond.find(tmpDate, 0)) != string::npos) + { + selectCond.replace(pos, tmpDate.length(), "DATE_FORMAT( f_date, '%Y%m%d') as f_date"); + } + + string sDbName = mSqlPart["dataid"]; + string ignoreKey(""); + + //不使用主键 + if(sDbName == "tars" || sDbName == "db_tarsstat") + { + ignoreKey = " IGNORE INDEX ( PRIMARY ) "; + } + + vector vGroupField = TC_Common::sepstr(groupField, ", "); + vector vSumField = TC_Common::sepstr(sumField, ", "); + + TC_Mysql tcMysql; + + TC_DBConf tcDbConf = conf; + /*if(bFlag) + { + tcDbConf = g_app.getDbInfo(iThread); + } + else + { + tcDbConf = g_app.getDbInfo(iThread); + }*/ + + tcDbConf._database = sDbName; + + tcMysql.init(tcDbConf); + + string sTbNamePre = tcDbConf._database + "_"; + + string sTbName(""); + string sSql(""); + //select range by f_date and f_tflag + for(string day = dateFrom; day <= dateTo; day = dateInc(day)) + { + for(string tflag = tflagFrom; tflag <= tflagTo && (tflag.substr(0,2) < "24"); tflag = tFlagInc(tflag)) + { + //table name:tars_2012060723 + sTbName = sTbNamePre + day + tflag.substr(0,2); + + sSql = "select " + selectCond + " from " + sTbName + " " + ignoreKey + whereCond + groupCond + " order by null;"; + + tars::TC_Mysql::MysqlData res = tcMysql.queryRecord(sSql); + + TLOGINFO(sUid << "res.size:" << res.size() << "|sSql:" << sSql << endl); + + // result is key:value pair; + //sKey 由groupby生成 + //value由index生成 + //int64_t t2Start = TNOWMS; + for(size_t iRow = 0; iRow < res.size(); iRow++) + { + string sKey = ""; + for(size_t j = 0; j < vGroupField.size(); j++) + { + sKey += sKey.empty()?"":","; + sKey += res[iRow][vGroupField[j]]; + } + + map >::iterator itResult = result.find(sKey); + if (itResult != result.end()) + { + vector& data = itResult->second; + for (size_t j = 0; j < vSumField.size() && j < data.size(); j++) + { + data[j] += TC_Common::strto(res[iRow][vSumField[j]]);// 相同key的值 求和 + } + } + else + { + vector& vRes = result[sKey]; + for(size_t j = 0; j < vSumField.size(); j++) + { + vRes.push_back( TC_Common::strto(res[iRow][vSumField[j]]));; + } + } + TLOGINFO("query iDb:" << iThread <<" {"<< sKey << ":" << TC_Common::tostr(result[sKey]) << "}" << endl); + } + + TLOGINFO("query iDb :" << iThread << " day:" << day <<" tflag:" << tflag << endl); + } + } //day + + sRes = "ret:0 iDb:" + TC_Common::tostr(iThread) + "\n"; + + //queryParam._atomic.inc(); + } + catch(TC_Mysql_Exception & ex) + { + sRes = "ret:-1|iDb:" + TC_Common::tostr(iThread) + string("|exception:") + ex.what() + "\n"; + TLOGERROR("query sUid:" << sUid << "query:" << sRes << endl); + + queryParam._run_result = -1; + //queryParam._atomic.inc(); + } + catch(exception & ex) + { + sRes = "ret:-1|iDb:" + TC_Common::tostr(iThread) + string("|exception:") + ex.what() + "\n"; + TLOGERROR("query sUid:" << sUid << "query:" << sRes << endl); + + queryParam._run_result = -1; + //queryParam._atomic.inc(); + } + int64_t tEnd = TNOWMS; + + TLOGDEBUG("query sUid:" << sUid << "exit query iDb:" << iThread <<"|timecost(ms):" << (tEnd - tStart) << "|res:" << sRes << endl); + + queryParam._atomic.inc(); + + if(queryParam._atomic.get() == queryParam._run_times) + { + { + TC_ThreadLock::Lock lock(queryParam._monitor); + queryParam._monitor.notifyAll(); + } + + TLOGDEBUG("query sUid:" << sUid << "notify query finish." << endl); + } + + +} + +/////////////////////////////////////////////////////////////////////////////// +string tFlagInc(const string& stflag) +{ + int h = TC_Common::strto(stflag.substr(0,2)); + int m = TC_Common::strto(stflag.substr(2,2)); + + h += 1; + char buf[5]; + snprintf(buf,sizeof(buf),"%.2d%.2d",h,m); + + return string(buf); +} +/////////////////////////////////////////////////////////////////////////////// +string dateInc(const string& sDate) +{ + string ret("20991231"); // 返回大数 + + try + { + int year = TC_Common::strto(sDate.substr(0, 4)); + int mon = TC_Common::strto(sDate.substr(4, 2)); + int day = TC_Common::strto(sDate.substr(6, 2)); + + struct tm *p = NULL; + time_t timep; + struct tm tt = {0}; + + time(&timep); + p=localtime_r(&timep, &tt); + p->tm_mon = mon -1; + p->tm_mday = day +1; + p->tm_year = year -1900 ; + + timep = mktime(p); + ret = TC_Common::tm2str(timep, "%Y%m%d"); + } + catch(exception & ex) + { + TLOGERROR("DbProxy::dateInc exception:" << ex.what() << endl); + } + return ret; +} +/////////////////////////////////////////////////////////////////////////////// +void selectLastMinTime(const string& sUid, int iThread , const string& tbname, const TC_DBConf& tcDbInfo, string & ret, QueryParam &queryParam) +{ + string sId = sUid; + try + { + string sTbNamePre = tbname + ".t_ecstatus"; + + //TLOGDEBUG("selectLastMinTime database name:" << tcDbConf._database << "|tbname:" << tbname << endl); + + TC_Mysql tcMysql; + tcMysql.init(tcDbInfo); + + int interval = g_app.getInsertInterval(); + time_t now = TC_TimeProvider::getInstance()->getNow(); + + string sDate,sFlag; + // 排除历史过期数据 + string sTime,sHour,sMinute; + time_t t = (now - interval * 60 * 2); + interval = g_app.getInsertInterval(); + t = (t/(interval*60))*interval*60; //要求必须为loadIntev整数倍 + t = (t%3600 == 0?t-60:t); //要求将9点写作0860 + sTime = TC_Common::tm2str(t,"%Y%m%d%H%M"); + sDate = sTime.substr(0,8); + sHour = sTime.substr(8,2); + sMinute = sTime.substr(10,2); + sFlag = sHour + (sMinute=="59"?"60":sMinute); //要求将9点写作0860 + + string sLast = sDate + " " + sFlag; + + string sSql = "select min(lasttime) as lasttime from "+ sTbNamePre+" where appname like '" +"%' and lasttime > '" + sLast + "'" ; + + tars::TC_Mysql::MysqlData res = tcMysql.queryRecord(sSql); + + if (res.size() > 0) + { + TLOGINFO("selectLastTime" << sId << "sSql:" << sSql << "|lasttime:" << res[0]["lasttime"] << endl); + + ret = res[0]["lasttime"]; + } + else + { + ret = ""; + } + //queryParam._atomic.inc(); + } + catch(TC_Mysql_Exception & ex) + { + TLOGERROR("selectLastTime sUid="<< sId <<"exception:"<< ex.what() << endl); + ret = ""; + queryParam._run_result = -1; + //queryParam._atomic.inc(); + } + catch(exception& e) + { + TLOGERROR("selectLastTime sUid="<< sId <<"exception:"<< e.what() << endl); + ret = ""; + queryParam._run_result = -1; + //queryParam._atomic.inc(); + } + + queryParam._atomic.inc(); + if(queryParam._atomic.get() == queryParam._run_times) + { + TC_ThreadLock::Lock lock(queryParam._monitor); + queryParam._monitor.notifyAll(); + TLOGDEBUG("query sUid:" << sId << "notify checktime finish." << endl); + } +} +/////////////////////////////////////////////////////////////////////////////// +string DbProxy::getLastTime(const map& mSqlPart) +{ + string sUid = mSqlPart.find("uid")->second; + + string min = "99999999999"; // 求最小的,初始使用很大的数据 + //TLOGDEBUG("mSqlPart"<< mSqlPart.find("dataid")->second < vDbInfo = g_app.getAllActiveDbInfo(); + + int iThreads = vDbInfo.size(); + + if(iThreads > 0) + { + vector res(iThreads); + + _queryParam._run_times = iThreads; + + int64_t tStart = TC_TimeProvider::getInstance()->getNowMs(); + + for (int i=0; i< iThreads; i++) + { + const string tbname = mSqlPart.find("dataid")->second; + auto fwrapper = std::bind(&selectLastMinTime, + std::cref(sUid), + i, + std::cref(tbname), + std::cref(vDbInfo[i]), + std::ref(res[i]), + std::ref(_queryParam)); + + g_app.getThreadPoolTimeCheck().exec(fwrapper); + } + + TLOGDEBUG("DbProxy::getLastTime sUid:" << sUid << "wait for getLastTime done." << endl); + + bool rc = true; + int ifail = 0; + while(_queryParam._atomic.get() != _queryParam._run_times) + { + { + TC_ThreadLock::Lock lock(_queryParam._monitor); + rc = _queryParam._monitor.timedWait(300); + } + + ++ifail; + + if(!rc) + { + if(ifail >= 10) + { + break; + } + } + } + + if(ifail >= 10) + { + TLOGDEBUG("DbProxy::getLastTime sUid:" << sUid << "wait for getLastTime timeout." << endl); + while(_queryParam._atomic.get() != _queryParam._run_times) + { + { + TC_ThreadLock::Lock lock(_queryParam._monitor); + _queryParam._monitor.timedWait(1000); + } + } + } + + if(_queryParam._atomic.get() == _queryParam._run_times) + rc = true; + /*bool rc = false; + { + TC_ThreadLock::Lock lock(_queryParam._monitor); + rc = _queryParam._monitor.timedWait(3000); + }*/ + + int64_t tEnd = TC_TimeProvider::getInstance()->getNowMs(); + + + if(rc) + { + TLOGDEBUG("DbProxy::getLastTime sUid:" << sUid << "getLastTime all done|return:" << _queryParam._run_result <<"|timecost(ms):" << (tEnd-tStart) << endl); + + for(int i = 0; i < iThreads; ++i) + { + if(res[i] < min) + { + min = res[i]; + } + } + } + else + { + min = ""; + TLOGDEBUG("DbProxy::getLastTime sUid:" << sUid << "getLastTime timeout." << endl); + } + } + else + { + min = ""; + } + + TLOGDEBUG("DbProxy::getLastTime sUid:" << sUid << "final lasttime:" << min << endl); + } + catch (exception &ex) + { + TLOGERROR("DbProxy::getLastTime exception:" << ex.what() << endl); + min = ""; + } + + _queryParam._run_times = 0; + _queryParam._run_result = 0; + _queryParam._atomic = 0; + + return min; +} + + +string DbProxy::makeResult(int iRet, const string& sRes) +{ + size_t act = g_app.getActiveDbInfo().size(); + int total = g_app.getDbInfo().size(); + string result = "Ret:" + TC_Common::tostr(iRet) + "\n" + + "ActiveDb:" + TC_Common::tostr(act) + "\n" + + "TotalDb:" + TC_Common::tostr(total) + "\n" + + sRes; + return result; +} diff --git a/QueryStatServer/DbProxy.h b/QueryStatServer/DbProxy.h new file mode 100644 index 00000000..373a7684 --- /dev/null +++ b/QueryStatServer/DbProxy.h @@ -0,0 +1,58 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __DB_PROXY_H_ +#define __DB_PROXY_H_ + +#include "util/tc_common.h" +#include "util/tc_thread.h" +#include "util/tc_option.h" +#include "util/tc_file.h" +#include "util/tc_mysql.h" +#include "util/tc_config.h" +#include "servant/TarsLogger.h" +#include "QueryServer.h" + +using namespace tars; + +class DbProxy +{ +public: + + DbProxy(); + + ~DbProxy(); + + void queryData(map& mSqlPart, string &sResult, bool bDbCountFlag); + + string getLastTime(const map& mSqlPart); + +private: + + int createRespHead(const vector &res, const string& sLasttime ,string& result, bool bDbCountFlag); + + int createRespData(const string& sUid, const map& mSqlPart, const vector > > &vDataList, const string& sHead, string &result); + + string makeResult(int iRet, const string& sRes); + +private: + QueryParam _queryParam; +}; + + +#endif + + diff --git a/QueryStatServer/DbThread.cpp b/QueryStatServer/DbThread.cpp new file mode 100644 index 00000000..718956ac --- /dev/null +++ b/QueryStatServer/DbThread.cpp @@ -0,0 +1,163 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "DbThread.h" +#include "util/tc_config.h" +#include "QueryServer.h" + + +DBThread::DBThread() +: _bTerminate(false) +{ + TLOGDEBUG("DBThread init ok" << endl); +} + +DBThread::~DBThread() +{ + if (isAlive()) + { + terminate(); + + getThreadControl().join(); + } + TLOGDEBUG("DBThread terminate." << endl); +} + +void DBThread::terminate() +{ + _bTerminate = true; + + TC_ThreadLock::Lock lock(*this); + + notifyAll(); +} + +void DBThread::run() +{ + TLOGDEBUG("DBThread::run begin." << endl); + while (!_bTerminate) + { + try + { + tryConnect(); + } + catch ( exception& ex ) + { + TLOGERROR("DBThread::run exception:" << ex.what() << endl); + + } + catch (... ) + { + TLOGERROR("DBThread::run unkonw exception catched" << endl); + } + TC_ThreadLock::Lock lock(*this); + timedWait(REAP_INTERVAL); + } +} + +int DBThread::connect(MYSQL** pstMql,const TC_DBConf& tcConf) +{ + + *pstMql = mysql_init(NULL); + if (mysql_real_connect(*pstMql,tcConf._host.c_str(), tcConf._user.c_str(), tcConf._password.c_str(), tcConf._database.c_str(), tcConf._port, NULL, tcConf._flag) == NULL) + { + TLOGERROR("[TC_Mysql::connect]: mysql_real_connect: " + string(mysql_error(*pstMql)) + ", erron:" < vDbInfo = g_app.getDbInfo(); + + // size_t iDbInfoSize = vDbInfo.size(); + + vector vDbCountInfo = g_app.getDbInfo(); + + size_t iDbCountInfoSize = vDbCountInfo.size(); + + + + vector vAtivedbCountInfo; + + + + for(size_t i = 0; i < vDbCountInfo.size(); i++) + { + TC_DBConf tcDBConf = vDbCountInfo[i]; + + + + MYSQL* _pstMql = NULL; + + int iRet = connect(&_pstMql,tcDBConf); + + if (_pstMql != NULL) + { + mysql_close(_pstMql); + _pstMql = NULL; + } + + if (iRet != 0) + { + TLOGERROR("DBThread::tryConnect new db host:" << tcDBConf._host << "|port:" << TC_Common::tostr(tcDBConf._port) << "|database:" << tcDBConf._database << endl); + string s("host"); + + s += tcDBConf._host; + s += "|port"; + s += TC_Common::tostr(tcDBConf._port); + s += "|database:"; + s += tcDBConf._database; + + sendAlarmSMS(s); + continue; + } + + vAtivedbCountInfo.push_back(vDbCountInfo[i]);; + } + + size_t iActiveDbCountInfoSize = vAtivedbCountInfo.size(); + + if(iDbCountInfoSize != iActiveDbCountInfoSize) + { + string sMsg = "statcount old db size:"; + sMsg += TC_Common::tostr(iDbCountInfoSize); + sMsg += "|statcount active db size:"; + sMsg += TC_Common::tostr(iActiveDbCountInfoSize); + sMsg += "|no equal."; + + sendAlarmSMS(sMsg); + } + + g_app.setActiveDb(vAtivedbCountInfo); + } + catch (exception& ex) + { + TLOGERROR("DBThread::tryConnect exception:"<< ex.what() << endl); + } +} + + + diff --git a/QueryStatServer/DbThread.h b/QueryStatServer/DbThread.h new file mode 100644 index 00000000..56766df5 --- /dev/null +++ b/QueryStatServer/DbThread.h @@ -0,0 +1,72 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __DB_THREAD_H_ +#define __DB_THREAD_H_ +#include +#include "util/tc_thread.h" +#include "util/tc_mysql.h" +#include "util/tc_common.h" +#include "servant/TarsLogger.h" + + +using namespace tars; + +/** + * 用于执行定时操作的线程类 + */ +class DBThread : public TC_Thread, public TC_ThreadLock +{ +public: + /** + * 定义常量 + */ + enum + { + REAP_INTERVAL = 30000 + }; + /** + * 构造 + */ + DBThread(); + + /** + * 析够 + */ + ~DBThread(); + + /** + * 结束线程 + */ + void terminate(); + + /** + * 轮询函数 + */ + virtual void run(); + + void tryConnect(); + + int connect(MYSQL **_pstMql,const TC_DBConf& tcConf); + + void sendAlarmSMS(const string &sMsg); + +private: + bool _bTerminate; + +}; + +#endif diff --git a/QueryStatServer/QueryDbThread.cpp b/QueryStatServer/QueryDbThread.cpp new file mode 100644 index 00000000..6a4a72c5 --- /dev/null +++ b/QueryStatServer/QueryDbThread.cpp @@ -0,0 +1,158 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "QueryDbThread.h" +#include "QueryServer.h" +#include "DbProxy.h" + +///////////////////////////////////////////////////////////////////////// +QueryDbThread::QueryDbThread() +: _terminate(false) +{ + TLOGDEBUG("QueryDbThread init ok" << endl); +} + +QueryDbThread::~QueryDbThread() +{ + terminate(); + + TLOGDEBUG("QueryDbThread terminate." << endl); +} + +void QueryDbThread::start(int iThreadNum) +{ + for(int i = 0; i < iThreadNum; ++i) + { + HandleThreadRunner *r = new HandleThreadRunner(this); + + r->start(); + + _runners.push_back(r); + } +} + +void QueryDbThread::terminate() +{ + _terminate = true; + + for (uint32_t i = 0; i < _runners.size(); ++i) + { + if (_runners[i]->isAlive()) + { + _runners[i]->terminate(); + + _queue.notifyT(); + } + } + + for (uint32_t i = 0; i < _runners.size(); ++i) + { + if(_runners[i]->isAlive()) + { + _runners[i]->getThreadControl().join(); + } + } + + _queue.clear(); + + for (uint32_t i = 0; i < _runners.size(); ++i) + { + if(_runners[i]) + { + delete _runners[i]; + _runners[i] = NULL; + } + } +} + +bool QueryDbThread::pop(QueryItem* &pItem) +{ + return _queue.pop_front(pItem, 2000); +} + +void QueryDbThread::put(QueryItem* pItem) +{ + if(!_terminate && pItem) + { + _queue.push_back(pItem); + } +} + +///////////////////////////////////////////////////////////////////////// +HandleThreadRunner::HandleThreadRunner(QueryDbThread* proc) +: _terminate(false) +, _proc(proc) +{ +} + +void HandleThreadRunner::terminate() +{ + _terminate = true; +} + +void HandleThreadRunner::run() +{ + string sRes(""); + DbProxy _dbproxy; + int64_t tStart = 0; + int64_t tEnd = 0; + + while (!_terminate) + { + QueryItem* pQueryItem = NULL; + + if(!_terminate && _proc->pop(pQueryItem)) + { + try + { + tStart = TNOWMS; + + _dbproxy.queryData(pQueryItem->mQuery, sRes, pQueryItem->bFlag); + + tEnd = TNOWMS; + + sRes += "endline\n"; + + pQueryItem->current->sendResponse(sRes.c_str(), sRes.length()); + + FDLOG("inout") << "HandleThreadRunner::run sUid:" << pQueryItem->sUid << "queryData timecost(ms):" << (tEnd - tStart) << endl; + } + catch(exception& ex) + { + TLOGERROR("HandleThreadRunner::run exception:" << ex.what() << endl); + + string sResult = "Ret:-1\n" + string(ex.what()) + "\nendline\n"; + pQueryItem->current->sendResponse(sResult.c_str(), sResult.length()); + + FDLOG("inout") << "HandleThreadRunner::run sUid:" << pQueryItem->sUid << "exception:" << ex.what() << endl; + } + catch(...) + { + TLOGERROR("HandleThreadRunner::run exception." << endl); + + string sResult = "Ret:-1\nunknown exception\nendline\n"; + pQueryItem->current->sendResponse(sResult.c_str(), sResult.length()); + + FDLOG("inout") << "HandleThreadRunner::run sUid:" << pQueryItem->sUid << "unknown exception." << endl; + } + + sRes = ""; + + delete pQueryItem; + pQueryItem = NULL; + } + } +} diff --git a/QueryStatServer/QueryDbThread.h b/QueryStatServer/QueryDbThread.h new file mode 100644 index 00000000..49496be1 --- /dev/null +++ b/QueryStatServer/QueryDbThread.h @@ -0,0 +1,78 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __QUERY_DB_BY_HASH_THREAD_H_ +#define __QUERY_DB_BY_HASH_THREAD_H_ + +#include +#include +#include "util/tc_thread.h" +#include "util/tc_mysql.h" +#include "util/tc_common.h" +#include "util/tc_thread_queue.h" +#include "QueryItem.h" + +using namespace tars; +using namespace std; + +////////////////////////////////////////////////////////////////////////////// +class QueryDbThread; + +////////////////////////////////////////////////////////////////////////////// +class HandleThreadRunner : public TC_Thread +{ +public: + + HandleThreadRunner(QueryDbThread* proc); + + virtual void run(); + + void terminate(); +private: + + bool _terminate; + + QueryDbThread * _proc; + +}; +////////////////////////////////////////////////////////////////////////////// +class QueryDbThread +{ +public: + + QueryDbThread(); + + ~QueryDbThread(); + + void terminate(); + + void start(int iThreadNum); + + void put(QueryItem* pItem); + + bool pop(QueryItem* &pItem); + + size_t getQueueSize() { return _queue.size(); }; + +private: + bool _terminate; + + TC_ThreadQueue _queue; + + vector _runners; +}; + +#endif diff --git a/QueryStatServer/QueryImp.cpp b/QueryStatServer/QueryImp.cpp new file mode 100644 index 00000000..b53839c0 --- /dev/null +++ b/QueryStatServer/QueryImp.cpp @@ -0,0 +1,143 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "QueryImp.h" +#include "RequestDecoder.h" +#include "QueryItem.h" +#include "servant/Application.h" + +using namespace std; + +////////////////////////////////////////////////////// +void QueryImp::initialize() +{ + //initialize servant here: + //... +} + +////////////////////////////////////////////////////// +void QueryImp::destroy() +{ + //destroy servant here: + //... +} + + +int QueryImp::doRequest(tars::TarsCurrentPtr current, vector& response) +{ + const vector& request = current->getRequestBuffer(); + string buf((const char*)(&request[0]), request.size()); + string sUid = TC_Common::tostr(g_app.genUid()) + "|"; + + FDLOG("inout") << "QueryImp::doRequest sUid:" << sUid << "doRequest input:" << buf << endl; + TLOGDEBUG(sUid << "QueryImp::doRequest sUid:" << sUid << "doRequest input:" << buf << endl); + + doQuery(sUid, buf, false, current); + + return 0; +} + +int QueryImp::doQuery(const string sUid, const string &sIn, bool bTarsProtocol, tars::TarsCurrentPtr current) +{ + try + { + size_t pos = sIn.rfind("}"); // find json end + + string s(""); + + if (pos != string::npos) + { + s = sIn.substr(0, pos+1); + } + else + { + throw TC_Exception("bad query string"); + } + + RequestDecoder decoder(s); + TLOGDEBUG("QueryImp::doQuery"<getNowMs(); + + string lasttime = _proxy.getLastTime(decoder.getSql()); + sResult += "lasttime:" + lasttime + "\n"; + sResult += "endline\n"; + + tEnd = TC_TimeProvider::getInstance()->getNowMs(); + + current->sendResponse(sResult.c_str(), sResult.length()); + + FDLOG("inout") << "QueryImp::doQuery time_check sUid:" << sUid << "send result succ,size:"<< sResult.length() << "|timecost(ms):" << (tEnd-tStart) << endl; + TLOGDEBUG("QueryImp::doQuery time_check sUid:" << sUid << "send result succ,size:"<< sResult.length() << "|timecost(ms):" << (tEnd-tStart) << endl); + } + + else if(ret == RequestDecoder::QUERY) + { + current->setResponse(false); + QueryItem * pItem = new QueryItem(); + pItem->sUid = sUid; + pItem->current = current; + pItem->mQuery = decoder.getSql(); + + map &mSqlPart = decoder.getSql(); + + map::iterator it; + for(it=mSqlPart.begin();it!=mSqlPart.end();it++) + { + TLOGDEBUG("QueryImp::mysql "<first<<"|"<second< vGroupField = TC_Common::sepstr(sGroupField, ", "); + + pItem->bFlag = true; + g_app.getThreadPoolQueryDb()->put(pItem); + + TLOGDEBUG("QueryImp::doQuery all dbcount." << endl); + } + else + { + TLOGERROR("QueryImp::doQuery " << sUid << "decode request failed\n" <sendResponse(sResult.c_str(), sResult.length()); + + FDLOG("inout") << "QueryImp::doQuery failed sUid:" << sUid << endl; + } + } + catch(exception &ex) + { + TLOGERROR("QueryImp::doQuery exception:" << ex.what() << endl); + string sResult = "Ret:-1\n" + string(ex.what()) + "\nendline\n"; + current->sendResponse(sResult.c_str(), sResult.length()); + + FDLOG("inout") << "QueryImp::doQuery exception sUid:" << sUid << endl; + } + return 0; +} diff --git a/QueryStatServer/QueryImp.h b/QueryStatServer/QueryImp.h new file mode 100644 index 00000000..4fb6c53c --- /dev/null +++ b/QueryStatServer/QueryImp.h @@ -0,0 +1,63 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef _QueryImp_H_ +#define _QueryImp_H_ + +#include "servant/Application.h" +#include "util/tc_common.h" +#include "util/tc_mysql.h" +#include "util/tc_config.h" +#include "DbProxy.h" + +/** + * + * + */ +class QueryImp : public tars::Servant +{ +public: + /** + * + */ + virtual ~QueryImp() {} + + /** + * + */ + virtual void initialize(); + + /** + * + */ + virtual void destroy(); + + /** + * + */ + + + virtual int doRequest(tars::TarsCurrentPtr current, vector& response); + + +private: + int doQuery(const string sUid, const string &sIn, bool bTarsProtocol, tars::TarsCurrentPtr current); + +private: + DbProxy _proxy; +}; +///////////////////////////////////////////////////// +#endif diff --git a/QueryStatServer/QueryItem.h b/QueryStatServer/QueryItem.h new file mode 100644 index 00000000..a44d0f68 --- /dev/null +++ b/QueryStatServer/QueryItem.h @@ -0,0 +1,43 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __QUERY_ITEM_H_ +#define __QUERY_ITEM_H_ + +#include +#include +#include "servant/Application.h" + +using namespace std; +using namespace tars; + +///////////////////////////////////////////////////////////////////// +class QueryItem +{ +public: + bool bFlag; + string sUid; + map mQuery; + tars::TarsCurrentPtr current; + + QueryItem() + : bFlag(false) + , sUid("") + , current(NULL) + {} +}; + +#endif diff --git a/QueryStatServer/QueryServer.cpp b/QueryStatServer/QueryServer.cpp new file mode 100644 index 00000000..cafbba70 --- /dev/null +++ b/QueryStatServer/QueryServer.cpp @@ -0,0 +1,242 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "QueryServer.h" +#include "QueryImp.h" + +using namespace std; + +QueryServer g_app; + +TC_Config * g_pconf; +///////////////////////////////////////////////////////////////// + +struct JsonProtocol +{ + + static int parse(string &in, string &out) + { + TLOGINFO("JsonProtocol parse:" << in << endl); + + string::size_type jsonEnd = in.find("}"); + + if (jsonEnd != string::npos ) + { + out = in; + in = ""; + return TC_EpollServer::PACKET_FULL; //返回1表示收到的包已经完全 + } + + return TC_EpollServer::PACKET_ERR; //返回-1表示收到包协议错误,框架会自动关闭当前连接 + } +}; + + + +void QueryServer::initialize() +{ + //initialize application here: + //... + vector v_dblist; + vector v_dbcountlist; + + g_pconf->getDomainVector("/tars/countdb", v_dbcountlist); + + size_t iDbNumber = v_dblist.size(); + + size_t iDbCountNumber = v_dbcountlist.size(); + + TLOGDEBUG("QueryServer::initialize stat dbstat size:" << iDbNumber << "|dbcount size:" << iDbCountNumber << endl); + + for(size_t i = 0; i < iDbCountNumber; i++) + { + TC_DBConf tcDBConf; + + string path= "/tars/countdb/" + v_dbcountlist[i]; + + tcDBConf.loadFromMap(g_pconf->getDomainMap(path)); + + _dbStatInfo.push_back(tcDBConf); + } + + _activeDbInfo = _dbStatInfo; + + _dBThread = new DBThread(); + + _dBThread->start(); + + _queryFlag.insert("f_date"); + _queryFlag.insert("f_tflag"); + _queryFlag.insert("master_name"); + _queryFlag.insert("slave_name"); + _queryFlag.insert("slave_ip"); + _queryFlag.insert("interface_name"); + + _insertInterval = TC_Common::strto(g_pconf->get("/tars","5")); + + size_t iDbThreadPoolSize = TC_Common::strto(g_pconf->get("/tars/threadpool","8")); + + size_t iTimeCheckPoolSize = TC_Common::strto(g_pconf->get("/tars/threadpool","8")); + + size_t iQueryDbPoolSize = TC_Common::strto(g_pconf->get("/tars/threadpool","4")); + + _timeCheck.init(iTimeCheckPoolSize); + + _timeCheck.start(); + + _poolDb.init(iDbThreadPoolSize); + + _poolDb.start(); + + _tpoolQueryDb = new QueryDbThread(); + + _tpoolQueryDb->start(iQueryDbPoolSize); + + vector vIpGroup = g_pconf->getDomainKey("/tars/notarsslavename"); + TLOGDEBUG("QueryServer::initialize vIpGroup size:" << vIpGroup.size() << endl); + for (unsigned i = 0; i < vIpGroup.size(); i++) + { + _notTarsSlaveName.insert(vIpGroup[i]); + TLOGDEBUG("QueryServer::initialize i:" << i << "|notarsslavename:" << vIpGroup[i] << endl); + } + addServant(ServerConfig::Application + "." + ServerConfig::ServerName + ".NoTarsObj"); + addServantProtocol(ServerConfig::Application + "." + ServerConfig::ServerName + ".NoTarsObj", &JsonProtocol::parse); +} +///////////////////////////////////////////////////////////////// + +void QueryServer::setActiveDb(const vector &vDbInfo) +{ + TC_LockT lock(*this); + _activeDbInfo = vDbInfo; +} + +vector QueryServer::getAllActiveDbInfo() const +{ + TC_LockT lock(*this); + vector vDbInfo; + for(size_t i = 0; i < _activeDbInfo.size(); ++i) + { + vDbInfo.push_back(_activeDbInfo[i]); + } + + return vDbInfo; +} + +vector QueryServer::getDbInfo() const +{ + TC_LockT lock(*this); + return _dbStatInfo; +} + +vector QueryServer::getActiveDbInfo() const +{ + TC_LockT lock(*this); + return _activeDbInfo; +} + +uint32_t QueryServer::genUid() +{ + TC_LockT lock(*this); + + while (++_uniqId == 0); + + return _uniqId; +} + +string QueryServer::dumpDbInfo(const vector& vDbInfo) const +{ + ostringstream os; + + os <::const_iterator it = _queryFlag.find(sKey); + if(it != _queryFlag.end()) + { + return true; + } + return false; +} + +set& QueryServer::getNotTarsSlaveName() +{ + return _notTarsSlaveName; +} + +///////////////////////////////////////////////////////////////// +void +QueryServer::destroyApp() +{ + //destroy application here: + //... + if(_dBThread) + { + delete _dBThread; + _dBThread = NULL; + } + + if(_tpoolQueryDb) + { + delete _tpoolQueryDb; + _tpoolQueryDb = NULL; + } + + bool b = _poolDb.waitForAllDone(1000); + + TLOGDEBUG("QueryServer::destroyApp waitForAllDone _poolDb return:" << b << "|getJobNum:" << _poolDb.getJobNum() << endl); + + _poolDb.stop(); + + b = _timeCheck.waitForAllDone(1000); + + TLOGDEBUG("QueryServer::destroyApp waitForAllDone _timeCheck return:" << b << "|getJobNum:" << _timeCheck.getJobNum() << endl); + + _timeCheck.stop(); +} +///////////////////////////////////////////////////////////////// +int +main(int argc, char* argv[]) +{ + try + { + g_pconf = & g_app.getConfig(); + g_app.main(argc, argv); + TarsTimeLogger::getInstance()->enableRemote("inout",false); + g_app.waitForShutdown(); + } + catch (std::exception& e) + { + cerr << "std::exception:" << e.what() << std::endl; + } + catch (...) + { + cerr << "unknown exception." << std::endl; + } + return -1; +} +///////////////////////////////////////////////////////////////// diff --git a/QueryStatServer/QueryServer.h b/QueryStatServer/QueryServer.h new file mode 100644 index 00000000..41da8f26 --- /dev/null +++ b/QueryStatServer/QueryServer.h @@ -0,0 +1,124 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef _QueryServer_H_ +#define _QueryServer_H_ + +#include +#include +#include "servant/Application.h" +#include "util/tc_thread_mutex.h" +#include "util/tc_lock.h" +#include "util/tc_thread_pool.h" +#include "util/tc_atomic.h" +#include "DbThread.h" +#include "QueryDbThread.h" + +using namespace std; +using namespace tars; + +///////////////////////////////////////////////////////////////////// +class QueryParam +{ +public: + int _run_times; + int _run_result; + TC_Atomic _atomic; + TC_ThreadLock _monitor; + + QueryParam() + : _run_times(0) + , _run_result(0) + , _atomic(0) + {} +}; +///////////////////////////////////////////////////////////////////// +class QueryServer : public Application , public TC_ThreadMutex +{ +public: + /** + * + **/ + virtual ~QueryServer() {}; + + /** + * + **/ + virtual void initialize(); + + /** + * + **/ + virtual void destroyApp(); + + int getInsertInterval() const { return _insertInterval; }; + + size_t getDbNumber() const { return _dbStatInfo.size(); } + + size_t getActiveDbSize() const { return _activeDbInfo.size(); } + + void setActiveDb( const vector &vDbInfo); + + vector getAllActiveDbInfo() const; + + vector getDbInfo() const; + + vector getActiveDbInfo() const; + + TC_DBConf getDbInfo(int iIndex) { return _dbStatInfo[iIndex]; } + + string dumpDbInfo(const vector& vDbInfo) const; + + uint32_t genUid(); + + TC_ThreadPool & getThreadPoolTimeCheck() { return _timeCheck; } + + TC_ThreadPool & getThreadPoolDb() { return _poolDb; } + + QueryDbThread * getThreadPoolQueryDb() { return _tpoolQueryDb; } + + bool searchQueryFlag(const string &sKey); + + //匹配非tars被调服务名 + set& getNotTarsSlaveName(); + +private: + uint32_t _uniqId; //唯一id + + int _insertInterval; //查询最后入库时间使用,入库耗时不会超过入库间隔,单位为分钟 + + DBThread * _dBThread; //定时检查数据库实例是否存活 + + QueryDbThread *_tpoolQueryDb; //用于处理数据库的查询操作 + + vector _dbStatInfo; //数据库信息 + + vector _activeDbInfo; //存活的数据库信息 + + set _queryFlag; //数据库字段 + + TC_ThreadPool _timeCheck; //处理timecheck操作的线程池 + + TC_ThreadPool _poolDb; //具体查询压缩维度后的数据库实例数据的线程池 + + + set _notTarsSlaveName; //匹配非tars被调服务名 +}; + +extern QueryServer g_app; +extern TC_Config * g_pconf; +//////////////////////////////////////////// +#endif diff --git a/QueryStatServer/RequestDecoder.cpp b/QueryStatServer/RequestDecoder.cpp new file mode 100644 index 00000000..7227067c --- /dev/null +++ b/QueryStatServer/RequestDecoder.cpp @@ -0,0 +1,501 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "DbProxy.h" +#include "util/tc_config.h" +#include "QueryServer.h" +#include "RequestDecoder.h" + +static string skey = ""; + + + +RequestDecoder::RequestDecoder(const string& input) +: _input(input) +, _slaveName("") +{ +} +RequestDecoder::~RequestDecoder() +{ + +} + +int RequestDecoder::generateVector(Document &d ,const string s,std::vector &v) +{ + + Value::ConstMemberIterator iter = d.FindMember(s.c_str()); + int i=0; + if (iter == d.MemberEnd()) + { + return 0; + } + else + { + if(iter->value.IsArray()) + { + for (Value::ConstValueIterator itr = iter->value.Begin(); itr != iter->value.End(); ++itr) + { + v.push_back(itr->GetString()); + ++i; + } + } + + else if (iter->value.IsString()) + { + v.push_back(iter->value.GetString()); + i=1; + } + + else + { + return 0; + } + + return i; + } + +} +int RequestDecoder::composeSqlPartition() +{ + vector vConditions; + int iRet=0; + + iRet=generateVector(_req,"filter",vConditions); + + if(iRet==0) + { + return -1; + } + + + string date1,date2; + + int ret = find_field(vConditions, "f_date", date1); + date1 = TC_Common::trim(date1, " ''"); + date1 = TC_Common::trim(date1, " "); + if (ret == EQ || ret ==-1) + { + + date2 = date1; + } + else //NOT EQ, find again + { + ret = find_field(vConditions, "f_date", date2); + date2 = TC_Common::trim(date2, " ''"); + date2 = TC_Common::trim(date2, " "); + if (date1 < date2) + { + + } + else + { + date1.swap(date2); + } + } + + _sql["date1"] = date1; + _sql["date2"] = date2; + //get date end + + //get hour + string tflag1,tflag2; + ret = find_field(vConditions, "f_tflag", tflag1); + tflag1 = TC_Common::trim(tflag1, " \"'"); + if (ret == EQ || ret == -1) + { + + tflag2 = tflag1; + } + else //NOT EQ, find again + { + ret = find_field(vConditions, "f_tflag", tflag2); + tflag2 = TC_Common::trim(tflag2, " \"'"); + if (tflag1 < tflag2) + { + + } + else + { + tflag1.swap(tflag2); + } + } + + _sql["tflag1"] = tflag1; + _sql["tflag2"] = tflag2; + //get hour end + + iRet=generateVector(_req,"filter",vConditions); + if (!vConditions.empty()) + { + string whereCond = ""; + vector::iterator it = vConditions.begin(); + while(it != vConditions.end()) + { + string &sTmp = *it; + string::size_type pos = sTmp.find("slave_name"); + if(pos != string::npos) + { + _slaveName = *it; + } + + whereCond += (whereCond.empty()?"":" and ") + *it ; + it++; + } + + string sWhere(""); + string::size_type ipos = whereCond.find("and istars="); + + if(ipos != string::npos) + { + + string spre = whereCond.substr(0, ipos); + + string snext = whereCond.substr(ipos+9); + + string::size_type ipos1 = snext.find("and"); + + if(ipos1 != string::npos) + { + string s = snext.substr(ipos1); + sWhere = spre; + sWhere += s; + + string sistars = whereCond.substr(ipos+4, (ipos + 9) + ipos1 - (ipos + 4)); + + string value(""); + + int flag = parseCondition(sistars, value); + + TLOGDEBUG("RequestDecoder::composeSqlPartition istars set|sistars:" << sistars << "|flag:" << flag << "|ipos:" << ipos << "|ipos1:" << ipos1 << "|snext:" << snext << endl); + + if(flag == EQ) + { + value = TC_Common::trim(value, " \"'"); + _sql["istars"] = value; + } + else if(flag == NE) + { + value = TC_Common::trim(value, " \"'"); + int iFlag = TC_Common::strto(value); + iFlag = !iFlag; + value = TC_Common::tostr(iFlag); + _sql["istars"] = value; + } + } + else + { + sWhere = spre; + + string sistars = whereCond.substr(ipos+4); + + string value(""); + + int flag = parseCondition(sistars, value); + + if(flag == EQ) + { + value = TC_Common::trim(value, " \"'"); + _sql["istars"] = value; + } + else if(flag == NE) + { + value = TC_Common::trim(value, " \"'"); + int iFlag = TC_Common::strto(value); + iFlag = !iFlag; + value = TC_Common::tostr(iFlag); + _sql["istars"] = value; + } + } + } + else + { + sWhere = whereCond; + } + + _sql["whereCond"] = " where " + sWhere; + + + } + + if(_slaveName != "") + { + string::size_type pos1 = _slaveName.find("'"); + if(pos1 != string::npos) + { + string::size_type pos2 = _slaveName.rfind("'"); + if(pos2 != pos1 && pos2 != string::npos) + { + _slaveName = _slaveName.substr(pos1, (pos2 - pos1 -1)); + } + } + } + + + + vConditions.clear(); + iRet=generateVector(_req,"groupby",vConditions); + + if (!vConditions.empty()) + { + string groupCond = ""; + string groupField = ""; + vector::iterator it = vConditions.begin(); + while(it != vConditions.end()) + { + groupCond += (groupCond.empty()?"":", ") + *it; + groupField += (groupField.empty()?"":", ") + *it; + it++; + } + _sql["groupCond"] = " group by " + groupCond; + _sql["groupField"] = groupField; + } + + string sumField = ""; + vConditions.clear(); + iRet=generateVector(_req,"indexs",vConditions); + if (vConditions.empty()) + { + sumField = " sum(succ_count) "; + } + else + { + vector::iterator it = vConditions.begin(); + while(it != vConditions.end()) + { + sumField += string((sumField.empty()?"":", ")) + " sum(" + *it + ")" ; + it++; + } + } + + _sql["sumField"]= sumField; + return 0; +} + +int RequestDecoder::parseCondition(const string& sCond, string& value) +{ + string::size_type pos =0; + pos= sCond.find(">="); + if (pos != string::npos ) + { + value = sCond.substr(pos+2); + return GE; + } + + pos = sCond.find("<="); + if (pos != string::npos ) + { + value = sCond.substr(pos+2); + return LE; + } + + pos = sCond.find("!="); + if (pos != string::npos ) + { + value = sCond.substr(pos+2); + return NE; + } + pos = sCond.find("<"); + if (pos != string::npos ) + { + value = sCond.substr(pos+1); + return LT; + } + + pos = sCond.find(">"); + if (pos != string::npos ) + { + value = sCond.substr(pos+1); + return GT; + } + + pos = sCond.find("="); + if (pos != string::npos ) + { + value = sCond.substr(pos+1); + return EQ; + } + return 0; +} + +int RequestDecoder::find_field(vector& vCond, const string& field /*f_tflag, f_date*/, string& value ) +{ + vector::iterator it = vCond.begin(); + while(it != vCond.end()){ + + string::size_type pos = it->find(field); + + if(pos != string::npos) + { + string temp = *it; + vCond.erase(it); + return parseCondition(temp, value); + } + it++; + } + return -1; +} + +/* +name : indexs, filter, groupby +*/ +int RequestDecoder::decodeDataid() +{ + + string::size_type pos = _input.find("dataid"); + if (pos == string::npos) + { + return -1; + } + string::size_type endpos = _input.find(",", pos); + _sql["dataid"] = _input.substr(pos + 9, endpos - pos -10); + LOG->debug() << "decodeDataid: " << _sql["dataid"] <debug() << "decodeMethod: " << _sql["method"] < &vFields) +{ + + string::size_type pos1 = arr.find_first_of("["); + if(pos1 == string::npos) + { + LOG->debug() << ("paramh '" + arr + "' is invalid!" ); + return -1; + } + string::size_type pos2 = arr.find_first_of("]"); + if(pos2 == string::npos) + { + LOG->debug() << ("paramh '" + arr + "' is invalid!" ); + return -1; + } + vFields = TC_Common::sepstr(arr.substr(pos1, pos2 -pos1-1), ","); + vector::iterator it = vFields.begin(); + while(it != vFields.end()) + { + + LOG->debug() << "indexs bt " << *it << endl; + string s = TC_Common::trim(*it, "[]\"\""); + *it = s; + LOG->debug() << "indexs at " << *it << endl; + it++; + } + return 0; + + +} + + +map& RequestDecoder::getSql() +{ + return _sql; +} + + +int RequestDecoder::decode() +{ + + _req.Parse(_input.c_str()); + if (_req.HasParseError()) { + TLOGERROR("Decode error:"<<_req.GetParseError()<<"|"<<_input); + return -1; + } + + try + { + vector vConditions ; + generateVector(_req,"method",vConditions); + if(vConditions.size()) + { + _sql["method"] =vConditions[0]; + TLOGDEBUG("Decode"<<_sql["method"]<error() << "RequestDecoder::decode exception:"<< ex.what() << endl; + return -1; + } + return -1; +} + +//传入sUid,供打印使用 +int RequestDecoder::addUid(const string& sUid) +{ + _sql["uid"] = sUid; + return 0; +} + +string RequestDecoder::getLine(const char** ppChar) +{ + string sTmp; + + sTmp.reserve(512); + + while((**ppChar) != '\r' && (**ppChar) != '\n' && (**ppChar) != '\0') + { + sTmp.append(1, (**ppChar)); + (*ppChar)++; + } + + if((**ppChar) == '\r') + { + (*ppChar)++; /* pass the char '\n' */ + } + + (*ppChar)++; + + return sTmp; +} + diff --git a/QueryStatServer/RequestDecoder.h b/QueryStatServer/RequestDecoder.h new file mode 100644 index 00000000..5d304b19 --- /dev/null +++ b/QueryStatServer/RequestDecoder.h @@ -0,0 +1,100 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __REQUEST_DECODE_H__ +#define __REQUEST_DECODE_H__ +#include +#include "util/tc_thread.h" +#include "util/tc_mysql.h" +#include "servant/StatF.h" +#include "util/tc_common.h" +#include "servant/TarsLogger.h" +#include "util/tc_thread.h" +#include "rapidjson/document.h" +#include "rapidjson/writer.h" +#include "rapidjson/stringbuffer.h" + +using namespace rapidjson; + +class RequestDecoder +{ +public: + static string getLine(const char** ppChar); +public: + enum Op + { + SET, + ADD, + SUB, + EQ, + NE, + GT, + LT, + LE, + GE, + LIMIT, + }; + + enum METHOD + { + QUERY = 0, + TIMECHECK, + }; + RequestDecoder(const string& input); + + ~RequestDecoder(); + + int parseCondition(const string& sCond, string& value); + + /** + * 从vCond中解析出field对应的值 + * + */ + int find_field(vector& vCond, const string& field /*f_tflag, f_date*/, string& value ); + + int decode(); + + int decodeDataid(); + + int decodeMethod(); + + int decodeArray(const string& arr, vector &vFields); + + int addUid(const string& sUid); + + map& getSql(); + + int composeSqlPartition(); + + string getQuerySlaveName() { return _slaveName; } + + int generateVector(Document &d ,const string s,std::vector &v); + +private: + //待解析的json请求串 + string _input; + + //解析json得到的数据库查询slave_name + string _slaveName; + + //解析json请求串得到的Dom 文件 + Document _req; + + //解析json得到的数据库查询条件值 + map _sql; +}; +#endif + diff --git a/README.md b/README.md new file mode 100644 index 00000000..7d62ef2d --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +[点我查看中文版](README.zh.md) + +This project is the basic service of the Tars framework and is the basic framework for the operation of the services that carry the TARS language. + + +Directory |Features +----------------------|---------------- +sql |Create scripts and sql tools for the database of the TARS framework runtime environment +conf |Template configuration for each basic service +protocol |Define communication interface files for each underlying service definition +RegistryServer |Name service routing +NodeServer |Management service +AdminRegistryServer |Access management service that interacts with the foreground +PatchServer |Publishing service +ConfigServer |Configuration service +LogServer |Log service +StatServer |Modular data statistics service +PropertyServer |Attribute statistics service +NotifyServer |Abnormal reporting service +deploy |Template configuration and tool scripts for core infrastructure services +tarscpp |The source implementation of the Tars RPC framework C++ language diff --git a/README.zh.md b/README.zh.md new file mode 100644 index 00000000..8a32c68e --- /dev/null +++ b/README.zh.md @@ -0,0 +1,19 @@ +该工程是Tars框架的基础服务,是承载TARS各个语言的服务运行的基础框架。 + + +目录名称 |功能 +----------------------|---------------- +sql |创建TARS框架运行环境的数据库的脚本和sql工具 +conf |各个基础服务的模版配置 +protocol |定义各个基础服务定义的通信接口文件 +RegistryServer |名字服务路由 +NodeServer |管理服务 +AdminRegistryServer |与前台进行交互的接入管理服务 +PatchServer |发布服务 +ConfigServer |配置服务 +LogServer |日志服务 +StatServer |模调数据统计服务 +PropertyServer |属性统计服务 +NotifyServer |异常上报统计服务 +deploy |核心基础服务的模版配置和工具脚本 +tarscpp |Tars RPC框架C++语言的源代实现 diff --git a/RegistryServer/CMakeLists.txt b/RegistryServer/CMakeLists.txt new file mode 100644 index 00000000..cfd1abf8 --- /dev/null +++ b/RegistryServer/CMakeLists.txt @@ -0,0 +1,7 @@ + +set(MODULE "tarsregistry") + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/deploy/${MODULE}/bin) + +#complice_module(${MODULE} "Registry.tars") +complice_module(${MODULE}) diff --git a/RegistryServer/CheckNodeThread.cpp b/RegistryServer/CheckNodeThread.cpp new file mode 100644 index 00000000..dace0d20 --- /dev/null +++ b/RegistryServer/CheckNodeThread.cpp @@ -0,0 +1,96 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "CheckNodeThread.h" + +extern TC_Config * g_pconf; + +CheckNodeThread::CheckNodeThread() +: _terminate(false) +, _nodeTimeout(60) +, _nodeTimeoutInterval(250) +{ +} + +CheckNodeThread::~CheckNodeThread() +{ + if (isAlive()) + { + terminate(); + notifyAll(); + getThreadControl().join(); + } +} + + +int CheckNodeThread::init() +{ + TLOGDEBUG("CheckNodeThread init"<((*g_pconf).get("/tars/reap", "250")); + _nodeTimeout = _nodeTimeout < 15 ? 15 : _nodeTimeout; + + _nodeTimeoutInterval = TC_Common::strto((*g_pconf).get("/tars/reap", "60")); + _nodeTimeoutInterval = _nodeTimeoutInterval < 15 ? 5 : _nodeTimeoutInterval; + + TLOGDEBUG("CheckNodeThread init ok."<getNow(); + //轮询心跳超时的node + if(tNow - tLastCheckNode >= _nodeTimeoutInterval) + { + _db.checkNodeTimeout(_nodeTimeout); + + tLastCheckNode = tNow; + } + + TC_ThreadLock::Lock lock(*this); + timedWait(1000); //ms + } + catch(exception & ex) + { + TLOGERROR("CheckNodeThread exception:" << ex.what() << endl); + } + catch(...) + { + TLOGERROR("CheckNodeThread unknown exception" << endl); + } + } +} + + + diff --git a/RegistryServer/CheckNodeThread.h b/RegistryServer/CheckNodeThread.h new file mode 100644 index 00000000..c566ccd9 --- /dev/null +++ b/RegistryServer/CheckNodeThread.h @@ -0,0 +1,82 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __CHECK_NODE_THREAD_H__ +#define __CHECK_NODE_THREAD_H__ + +#include +#include "util/tc_thread.h" +#include "DbHandle.h" + +using namespace tars; + +////////////////////////////////////////////////////// +/** + * 监控tarsnode超时的线程类 + */ +class CheckNodeThread : public TC_Thread, public TC_ThreadLock +{ +public: + + /** + * 构造函数 + */ + CheckNodeThread(); + + /** + * 析构函数 + */ + ~CheckNodeThread(); + + /** + * 结束线程 + */ + void terminate(); + + /** + * 初始化 + */ + int init(); + + /** + * 轮询函数 + */ + virtual void run(); + +protected: + /* + * 线程结束标志 + */ + bool _terminate; + + /* + * 数据库操作 + */ + CDbHandle _db; + + /* + * node心跳超时时间 + */ + int _nodeTimeout; + + /* + * 线程检查周期 + */ + int _nodeTimeoutInterval; + +}; + +#endif diff --git a/RegistryServer/CheckSettingState.cpp b/RegistryServer/CheckSettingState.cpp new file mode 100644 index 00000000..517ca643 --- /dev/null +++ b/RegistryServer/CheckSettingState.cpp @@ -0,0 +1,97 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "CheckSettingState.h" +#include "servant/TarsLogger.h" + +extern TC_Config * g_pconf; + +CheckSettingState::CheckSettingState() +: _terminate(false) +, _checkingInterval(10) +, _leastChangedTime(10*60) +{ +} + +CheckSettingState::~CheckSettingState() +{ + if (isAlive()) + { + terminate(); + notifyAll(); + getThreadControl().join(); + } +} + +int CheckSettingState::init() +{ + TLOGDEBUG("CheckSettingStateThread init"<((*g_pconf).get("/tars/reap", "10")); + _checkingInterval = _checkingInterval < 5 ? 5 : _checkingInterval; + + _leastChangedTime = TC_Common::strto((*g_pconf).get("/tars/reap", "600")); + _leastChangedTime = _leastChangedTime < 60 ? 60 : _leastChangedTime; + + TLOGDEBUG("CheckSettingStateThread init ok."<getNow(); + + //核查各server在node的设置状态 + if(tNow - tLastQueryServer >= _checkingInterval) + { + _db.checkSettingState(_leastChangedTime); + + //执行完成后再赋当前时间值 + tLastQueryServer = TC_TimeProvider::getInstance()->getNow(); + } + + TC_ThreadLock::Lock lock(*this); + timedWait(100); //ms + } + catch(exception & ex) + { + TLOGERROR("CheckSettingState exception:" << ex.what() << endl); + } + catch(...) + { + TLOGERROR("CheckSettingState unknown exception." << endl); + } + } +} + diff --git a/RegistryServer/CheckSettingState.h b/RegistryServer/CheckSettingState.h new file mode 100644 index 00000000..f1f38880 --- /dev/null +++ b/RegistryServer/CheckSettingState.h @@ -0,0 +1,83 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __CHECKSETINGSTATE_H__ +#define __CHECKSETINGSTATE_H__ + +#include + +#include "util/tc_thread.h" +#include "Node.h" +#include "DbHandle.h" + +using namespace tars; + +////////////////////////////////////////////////////// +/** + * 用于执行定时操作的线程类 + */ +class CheckSettingState : public TC_Thread, public TC_ThreadLock +{ +public: + + /* + * 构造函数 + */ + CheckSettingState(); + + /* + * 析构函数 + */ + ~CheckSettingState(); + + /* + * 结束线程 + */ + void terminate(); + + /** + * 初始化 + */ + int init(); + + /** + * 线程执行函数 + */ + virtual void run(); + +private: + /* + * 线程结束标志 + */ + bool _terminate; + + /* + * 数据库操作 + */ + CDbHandle _db; + + /* + * 轮询server状态的间隔时间 + */ + int _checkingInterval; + + /* + * 增量查询服务状态的时间,单位是秒 + */ + int _leastChangedTime; +}; + +#endif diff --git a/RegistryServer/DbHandle.cpp b/RegistryServer/DbHandle.cpp new file mode 100644 index 00000000..2cf80931 --- /dev/null +++ b/RegistryServer/DbHandle.cpp @@ -0,0 +1,1800 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include +#include +#include "DbHandle.h" +#include "RegistryServer.h" + +TC_ReadersWriterData CDbHandle::_objectsCache; + +TC_ReadersWriterData > CDbHandle::_mapGroupPriority; + +std::map CDbHandle::_mapServantStatus; +TC_ThreadLock CDbHandle::_mapServantStatusLock; + +map CDbHandle::_mapNodePrxCache; +TC_ThreadLock CDbHandle::_NodePrxLock; + +//key-ip, value-组编号 +TC_ReadersWriterData > CDbHandle::_groupIdMap; +//key-group_name, value-组编号 +TC_ReadersWriterData > CDbHandle::_groupNameMap; + +TC_ReadersWriterData CDbHandle::_setDivisionCache; + +extern RegistryServer g_app; +extern TC_Config *g_pconf; + +int CDbHandle::init(TC_Config *pconf) +{ + try + { + TC_DBConf tcDBConf; + tcDBConf.loadFromMap(pconf->getDomainMap("/tars/db")); + string option = pconf->get("/tars/db", ""); + if (!option.empty() && option == "CLIENT_MULTI_STATEMENTS") + { + tcDBConf._flag = CLIENT_MULTI_STATEMENTS; + _enMultiSql = true; + TLOGDEBUG("CDbHandle::init tcDBConf._flag: " << option << endl); + } + _mysqlReg.init(tcDBConf); + } + catch (TC_Config_Exception& ex) + { + TLOGERROR("CDbHandle::init exception: " << ex.what() << endl); + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::init exception: " << ex.what() << endl); + exit(0); + } + + return 0; +} + +int CDbHandle::registerNode(const string& name, const NodeInfo& ni, const LoadInfo& li) +{ + try + { + string sSelectSql = "select present_state, node_obj, template_name " + "from t_node_info " + "where node_name='" + _mysqlReg.escapeString(name) + "'"; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sSelectSql); + TLOGDEBUG("CDbHandle::init select node affected:" << res.size() << endl); + + string sTemplateName; + if (res.size() != 0) + { + //合法性判断,是否存在名字相同已经存活但node obj不同的注册节点 + if (res[0]["present_state"] == "active" && res[0]["node_obj"] != ni.nodeObj) + { + TLOGERROR("registery node :" << name << " error, other node has registered." << endl); + return 1; + } + //传递已配置的模板名 + sTemplateName = res[0]["template_name"]; + } + + string sSql = "replace into t_node_info " + " (node_name, node_obj, endpoint_ip, endpoint_port, data_dir, load_avg1, load_avg5, load_avg15," + " last_reg_time, last_heartbeat, setting_state, present_state, tars_version, template_name)" + "values('" + _mysqlReg.escapeString(name) + "', '" + _mysqlReg.escapeString(ni.nodeObj) + "', " + " '" + _mysqlReg.escapeString(ni.endpointIp) + "'," + " '" + tars::TC_Common::tostr(ni.endpointPort) + "'," + " '" + _mysqlReg.escapeString(ni.dataDir) + "','" + tars::TC_Common::tostr(li.avg1) + "'," + " '" + tars::TC_Common::tostr(li.avg5) + "'," + " '" + tars::TC_Common::tostr(li.avg15) + "', now(), now(), 'active', 'active', " + + " '" + _mysqlReg.escapeString(ni.version) + "', '" + _mysqlReg.escapeString(sTemplateName) + "')"; + + _mysqlReg.execute(sSql); + + TLOGDEBUG("registry node :" << name << " affected:" << _mysqlReg.getAffectedRows() << endl); + + NodePrx nodePrx; + g_app.getCommunicator()->stringToProxy(ni.nodeObj, nodePrx); + + TC_ThreadLock::Lock lock(_NodePrxLock); + _mapNodePrxCache[name] = nodePrx; + + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::init " << name << " exception: " << ex.what() << endl); + return 2; + } + catch (tars::TarsException& ex) + { + TLOGERROR("CDbHandle::init " << name << " exception: " << ex.what() << endl); + return 3; + } + + return 0; +} + +int CDbHandle::destroyNode(const string& name) +{ + try + { + string sSql = "update t_node_info as node " + "left join t_server_conf as server using (node_name) " + "set node.present_state = 'inactive', server.present_state='inactive' " + "where node.node_name='" + _mysqlReg.escapeString(name) + "'"; + + _mysqlReg.execute(sSql); + + TLOGDEBUG("CDbHandle::destroyNode " << name << " affected:" << _mysqlReg.getAffectedRows() << endl); + + TC_ThreadLock::Lock lock(_NodePrxLock); + _mapNodePrxCache.erase(name); + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::destroyNode " << name << " exception: " << ex.what() << endl); + } + + return 0; +} + + +int CDbHandle::keepAlive(const string& name, const LoadInfo& li) +{ + try + { + int64_t iStart = TNOWMS; + string sSql = "update t_node_info " + "set last_heartbeat=now(), present_state='active'," + " load_avg1=" + tars::TC_Common::tostr(li.avg1) + "," + " load_avg5=" + tars::TC_Common::tostr(li.avg5) + "," + " load_avg15=" + tars::TC_Common::tostr(li.avg15) + " " + "where node_name='" + _mysqlReg.escapeString(name) + "'"; + + _mysqlReg.execute(sSql); + + TLOGDEBUG("CDbHandle::keepAlive " << name << " affected:" << _mysqlReg.getAffectedRows() << "|cost:" << (TNOWMS - iStart) << endl); + + if (_mysqlReg.getAffectedRows() == 0) + { + return 1; + } + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::keepAlive " << name << " exception: " << ex.what() << endl); + return 2; + } + + return 0; +} + +map CDbHandle::getActiveNodeList(string& result) +{ + map mapNodeList; + try + { + string sSql = "select node_name, node_obj from t_node_info " + "where present_state='active'"; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sSql); + + TLOGDEBUG("CDbHandle::getActiveNodeList (present_state='active') affected:" << res.size() << endl); + + for (unsigned i = 0; i < res.size(); i++) + { + mapNodeList[res[i]["node_name"]] = res[i]["node_obj"]; + } + } + catch (TC_Mysql_Exception& ex) + { + result = string(__FUNCTION__) + " exception: " + ex.what(); + TLOGERROR(result << endl); + return mapNodeList; + } + + return mapNodeList; +} + +int CDbHandle::getNodeVersion(const string& nodeName, string& version, string& result) +{ + try + { + string sSql = "select tars_version from t_node_info " + "where node_name='" + _mysqlReg.escapeString(nodeName) + "'"; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sSql); + + TLOGDEBUG("CDbHandle::getNodeVersion (node_name='" << nodeName << "') affected:" << res.size() << endl); + + if (res.size() > 0) + { + version = res[0]["tars_version"]; + return 0; + + } + result = "node_name(" + nodeName + ") int table t_node_info not exist"; + } + catch (TC_Mysql_Exception& ex) + { + + TLOGERROR("CDbHandle::getNodeVersion exception:"< CDbHandle::getServers(const string& app, const string& serverName, const string& nodeName, bool withDnsServer) +{ + string sSql; + vector vServers; + unsigned num = 0; + int64_t iStart = TNOWMS; + + try + { + //server详细配置 + string sCondition; + sCondition += "server.node_name='" + _mysqlReg.escapeString(nodeName) + "'"; + if (app != "") sCondition += " and server.application='" + _mysqlReg.escapeString(app) + "' "; + if (serverName != "") sCondition += " and server.server_name='" + _mysqlReg.escapeString(serverName) + "' "; + if (withDnsServer == false) sCondition += " and server.server_type !='tars_dns' "; //不获取dns服务 + + sSql = "select server.application, server.server_name, server.node_name, base_path, " + " exe_path, setting_state, present_state, adapter_name, thread_num, async_thread_num, endpoint," + " profile,template_name, " + " allow_ip, max_connections, servant, queuecap, queuetimeout,protocol,handlegroup," + " patch_version, patch_time, patch_user, " + " server_type, start_script_path, stop_script_path, monitor_script_path,config_center_port ," + " enable_set, set_name, set_area, set_group " + "from t_server_conf as server " + " left join t_adapter_conf as adapter using(application, server_name, node_name) " + "where " + sCondition; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sSql); + num = res.size(); + //对应server在vector的下标 + map mapAppServerTemp; + + //获取模版profile内容 + map mapProfile; + + //分拆数据到server的信息结构里 + for (unsigned i = 0; i < res.size(); i++) + { + string sServerId = res[i]["application"] + "." + res[i]["server_name"] + + "_" + res[i]["node_name"]; + + if (mapAppServerTemp.find(sServerId) == mapAppServerTemp.end()) + { + //server配置 + ServerDescriptor server; + server.application = res[i]["application"]; + server.serverName = res[i]["server_name"]; + server.nodeName = res[i]["node_name"]; + server.basePath = res[i]["base_path"]; + server.exePath = res[i]["exe_path"]; + server.settingState = res[i]["setting_state"]; + server.presentState = res[i]["present_state"]; + server.patchVersion = res[i]["patch_version"]; + server.patchTime = res[i]["patch_time"]; + server.patchUser = res[i]["patch_user"]; + server.profile = res[i]["profile"]; + server.serverType = res[i]["server_type"]; + server.startScript = res[i]["start_script_path"]; + server.stopScript = res[i]["stop_script_path"]; + server.monitorScript = res[i]["monitor_script_path"]; + server.configCenterPort = TC_Common::strto(res[i]["config_center_port"]); + + server.setId = ""; + if (TC_Common::lower(res[i]["enable_set"]) == "y") + { + server.setId = res[i]["set_name"] + "." + res[i]["set_area"] + "." + res[i]["set_group"]; + } + + //获取父模版profile内容 + if (mapProfile.find(res[i]["template_name"]) == mapProfile.end()) + { + string sResult; + mapProfile[res[i]["template_name"]] = getProfileTemplate(res[i]["template_name"], sResult); + } + + TC_Config tParent, tProfile; + tParent.parseString(mapProfile[res[i]["template_name"]]); + tProfile.parseString(server.profile); + + int iDefaultAsyncThreadNum = 3; + + if("tars_nodejs" == server.serverType) + { + //tars_nodejs类型的业务需要设置这个值为0 + iDefaultAsyncThreadNum = 0; + } + + int iConfigAsyncThreadNum = TC_Common::strto(TC_Common::trim(res[i]["async_thread_num"])); + iDefaultAsyncThreadNum = iConfigAsyncThreadNum > iDefaultAsyncThreadNum ? iConfigAsyncThreadNum : iDefaultAsyncThreadNum; + server.asyncThreadNum = TC_Common::strto(tProfile.get("/tars/application/client", TC_Common::tostr(iDefaultAsyncThreadNum))); + tParent.joinConfig(tProfile, true); + server.profile = tParent.tostr(); + + mapAppServerTemp[sServerId] = vServers.size(); + vServers.push_back(server); + } + + //adapter配置 + AdapterDescriptor adapter; + adapter.adapterName = res[i]["adapter_name"]; + if (adapter.adapterName == "") + { + //adapter没配置,left join 后为 NULL,不放到adapters map + continue; + } + + adapter.threadNum = res[i]["thread_num"]; + adapter.endpoint = res[i]["endpoint"]; + adapter.maxConnections = TC_Common::strto(res[i]["max_connections"]); + adapter.allowIp = res[i]["allow_ip"]; + adapter.servant = res[i]["servant"]; + adapter.queuecap = TC_Common::strto(res[i]["queuecap"]); + adapter.queuetimeout = TC_Common::strto(res[i]["queuetimeout"]); + adapter.protocol = res[i]["protocol"]; + adapter.handlegroup = res[i]["handlegroup"]; + + vServers[mapAppServerTemp[sServerId]].adapters[adapter.adapterName] = adapter; + } + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::getServers " << app << "." << serverName << "_" << nodeName + << " exception: " << ex.what() << "|" << sSql << endl); + return vServers; + } + catch (TC_Config_Exception& ex) + { + TLOGERROR("CDbHandle::getServers " << app << "." << serverName << "_" << nodeName + << " TC_Config_Exception exception: " << ex.what() << endl); + throw TarsException(string("TC_Config_Exception exception: ") + ex.what()); + } + + TLOGDEBUG(app << "." << serverName << "_" << nodeName << " getServers affected:" << num + << "|cost:" << (TNOWMS - iStart) << endl); + + return vServers; + +} + +string CDbHandle::getProfileTemplate(const string& sTemplateName, string& sResultDesc) +{ + map mapRecursion; + return getProfileTemplate(sTemplateName, mapRecursion, sResultDesc); +} + +string CDbHandle::getProfileTemplate(const string& sTemplateName, map& mapRecursion, string& sResultDesc) +{ + try + { + string sSql = "select template_name, parents_name, profile from t_profile_template " + "where template_name='" + _mysqlReg.escapeString(sTemplateName) + "'"; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sSql); + + if (res.size() == 0) + { + sResultDesc += "(" + sTemplateName + ":template not found)"; + return ""; + } + + TC_Config confMyself, confParents; + confMyself.parseString(res[0]["profile"]); + //mapRecursion用于避免重复继承 + mapRecursion[res[0]["template_name"]] = 1; + + if (res[0]["parents_name"] != "" && mapRecursion.find(res[0]["parents_name"]) == mapRecursion.end()) + { + confParents.parseString(getProfileTemplate(res[0]["parents_name"], mapRecursion, sResultDesc)); + confMyself.joinConfig(confParents, false); + } + sResultDesc += "(" + sTemplateName + ":OK)"; + + TLOGDEBUG("CDbHandle::getProfileTemplate " << sTemplateName << " " << sResultDesc << endl); + + return confMyself.tostr(); + } + catch (TC_Mysql_Exception& ex) + { + sResultDesc += "(" + sTemplateName + ":" + ex.what() + ")"; + TLOGERROR("CDbHandle::getProfileTemplate exception: " << ex.what() << endl); + } + catch (TC_Config_Exception& ex) + { + sResultDesc += "(" + sTemplateName + ":" + ex.what() + ")"; + TLOGERROR("CDbHandle::getProfileTemplate TC_Config_Exception exception: " << ex.what() << endl); + } + + return ""; +} + +vector CDbHandle::getAllApplicationNames(string& result) +{ + vector vApps; + try + { + string sSql = "select distinct application from t_server_conf"; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sSql); + TLOGDEBUG("CDbHandle::getAllApplicationNames affected:" << res.size() << endl); + + for (unsigned i = 0; i < res.size(); i++) + { + vApps.push_back(res[i]["application"]); + } + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::getAllApplicationNames exception: " << ex.what() << endl); + return vApps; + } + + return vApps; +} + +vector > CDbHandle::getAllServerIds(string& result) +{ + vector > vServers; + try + { + string sSql = "select application, server_name, node_name, setting_state, present_state,server_type from t_server_conf"; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sSql); + TLOGDEBUG("CDbHandle::getAllServerIds affected:" << res.size() << endl); + + for (unsigned i = 0; i < res.size(); i++) + { + vector server; + server.push_back(res[i]["application"] + "." + res[i]["server_name"] + "_" + res[i]["node_name"]); + server.push_back(res[i]["setting_state"]); + server.push_back(res[i]["present_state"]); + server.push_back(res[i]["server_type"]); + vServers.push_back(server); + } + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::getAllServerIds exception: " << ex.what() << endl); + return vServers; + } + + return vServers; + +} +int CDbHandle::updateServerState(const string& app, const string& serverName, const string& nodeName, const string& stateFields, tars::ServerState state, int processId) +{ + try + { + int64_t iStart = TNOWMS; + if (stateFields != "setting_state" && stateFields != "present_state") + { + TLOGDEBUG(app << "." << serverName << "_" << nodeName + << " not supported fields:" << stateFields << endl); + return -1; + } + + string sProcessIdSql = (stateFields == "present_state" ? + (", process_id = " + TC_Common::tostr(processId) + " ") : ""); + + string sSql = "update t_server_conf " + "set " + stateFields + " = '" + etos(state) + "' " + sProcessIdSql + + "where application='" + _mysqlReg.escapeString(app) + "' " + " and server_name='" + _mysqlReg.escapeString(serverName) + "' " + " and node_name='" + _mysqlReg.escapeString(nodeName) + "' "; + + _mysqlReg.execute(sSql); + TLOGDEBUG("CDbHandle::updateServerState " << app << "." << serverName << "_" << nodeName + << " affected:" << _mysqlReg.getAffectedRows() + << "|cost:" << (TNOWMS - iStart) << endl); + + { + TC_ThreadLock::Lock lock(_mapServantStatusLock); + ServantStatusKey statusKey = { app, serverName, nodeName }; + _mapServantStatus[statusKey] = static_cast(state); + } + return 0; + + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::updateServerState " << app << "." << serverName << "_" << nodeName + << " exception: " << ex.what() << endl); + return -1; + } +} + +int CDbHandle::updateServerStateBatch(const std::vector& vecStateInfo) +{ + const size_t sizeStep = 1000; + + for (std::vector::size_type i = 0; i < vecStateInfo.size();) + { + int iEnd = (i + sizeStep >= vecStateInfo.size()) ? vecStateInfo.size() : (i + sizeStep); + if (doUpdateServerStateBatch(vecStateInfo, i, iEnd) != 0) return -1; + i = iEnd; + } + + return 0; +} + +int CDbHandle::doUpdateServerStateBatch(const std::vector& vecStateInfo, const size_t sizeBegin, const size_t sizeEnd) +{ + std::map > > map_sort; + + { + TC_ThreadLock::Lock lock(_mapServantStatusLock); + for (std::vector::size_type i = sizeBegin; i < sizeEnd; i++) + { + ServantStatusKey statusKey = { vecStateInfo[i].application, vecStateInfo[i].serverName, vecStateInfo[i].nodeName }; + std::map::iterator it = _mapServantStatus.find(statusKey); + if (it != _mapServantStatus.end() && it->second == static_cast(vecStateInfo[i].serverState)) continue; + + map_sort[vecStateInfo[i].application][vecStateInfo[i].serverName].push_back(i); + } + } + + if (map_sort.empty()) + { + TLOGDEBUG("CDbHandle::doUpdateServerStateBatch vector size(" << vecStateInfo.size() << ") do nothing within the same state in cache" << endl); + return 0; + } + + std::string sCommand; + //新更新的状态,等语句更新成功后赋值 + std::map updated_map; + try + { + int64_t iStart = TC_TimeProvider::getInstance()->getNowMs(); + + if (_enMultiSql) + { + std::string sPrefix = "UPDATE t_server_conf SET present_state='"; + for (std::map > >::iterator it_app = map_sort.begin(); it_app != map_sort.end(); it_app++) + { + for (std::map >::iterator it_svr = it_app->second.begin(); it_svr != it_app->second.end(); it_svr++) + { + for (std::vector::size_type i = 0; i < it_svr->second.size(); i++) + { + sCommand += (sCommand == "" ? "" : ";") + sPrefix + etos(vecStateInfo[it_svr->second[i]].serverState) + + "', process_id= " + TC_Common::tostr(vecStateInfo[it_svr->second[i]].processId) + + " WHERE application='" + _mysqlReg.escapeString(it_app->first) + + "' AND server_name='" + _mysqlReg.escapeString(it_svr->first) + + "' AND node_name='" + _mysqlReg.escapeString(vecStateInfo[it_svr->second[i]].nodeName) + "'"; + + ServantStatusKey statusKey = { it_app->first, it_svr->first, vecStateInfo[it_svr->second[i]].nodeName }; + updated_map[statusKey] = vecStateInfo[it_svr->second[i]].serverState; + } + } + } + } + else + { + std::string sPidCommand, sPreCommand; + for (std::map > >::iterator it_app = map_sort.begin(); it_app != map_sort.end(); it_app++) + { + sPidCommand += " WHEN '" + it_app->first + "' THEN CASE server_name "; + sPreCommand += " WHEN '" + it_app->first + "' THEN CASE server_name "; + + for (std::map >::iterator it_svr = it_app->second.begin(); it_svr != it_app->second.end(); it_svr++) + { + sPidCommand += " WHEN '" + it_svr->first + "' THEN CASE node_name "; + sPreCommand += " WHEN '" + it_svr->first + "' THEN CASE node_name "; + + for (std::vector::size_type i = 0; i < it_svr->second.size(); i++) + { + sPidCommand += " WHEN '" + _mysqlReg.escapeString(vecStateInfo[it_svr->second[i]].nodeName) + "' THEN " + TC_Common::tostr(vecStateInfo[it_svr->second[i]].processId); + sPreCommand += " WHEN '" + _mysqlReg.escapeString(vecStateInfo[it_svr->second[i]].nodeName) + "' THEN '" + etos(vecStateInfo[it_svr->second[i]].serverState) + "'"; + + ServantStatusKey statusKey = { it_app->first, it_svr->first, vecStateInfo[it_svr->second[i]].nodeName }; + updated_map[statusKey] = vecStateInfo[it_svr->second[i]].serverState; + + } + + sPidCommand += " ELSE process_id END"; + sPreCommand += " ELSE present_state END"; + } + + sPidCommand += " ELSE process_id END"; + sPreCommand += " ELSE present_state END"; + } + sCommand = "UPDATE t_server_conf SET process_id= CASE application " + sPidCommand + " ELSE process_id END, present_state= CASE application " + sPreCommand + " ELSE present_state END"; + } + + if (!sCommand.empty()) + { + _mysqlReg.execute(sCommand); + int iRows = 0; + if (_enMultiSql) + { + for (iRows = mysql_affected_rows(_mysqlReg.getMysql()); !mysql_next_result(_mysqlReg.getMysql()); + iRows += mysql_affected_rows(_mysqlReg.getMysql())) ; + } + else + { + iRows = mysql_affected_rows(_mysqlReg.getMysql()); + } + + if (iRows > 0) + { + TLOGDEBUG("CDbHandle::doUpdateServerStateBatch sql: " << sCommand << " vector:" << vecStateInfo.size() << " affected:" << iRows + << "|cost:" << (TNOWMS - iStart) << endl); + + TC_ThreadLock::Lock lock(_mapServantStatusLock); + _mapServantStatus.insert(updated_map.begin(), updated_map.end()); + } + } + return 0; + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::doUpdateServerStateBatch exception: " << ex.what() << " sql:" << sCommand << endl); + return -1; + } + catch (exception& ex) + { + TLOGERROR("CDbHandle::doUpdateServerStateBatch " << ex.what() << endl); + return -1; + } + return -1; +} + +int CDbHandle::setPatchInfo(const string& app, const string& serverName, const string& nodeName, const string& version, const string& user) +{ + try + { + string sSql = "update t_server_conf " + "set patch_version = '" + _mysqlReg.escapeString(version) + "', " + " patch_user = '" + _mysqlReg.escapeString(user) + "', " + " patch_time = now() " + "where application='" + _mysqlReg.escapeString(app) + "' " + " and server_name='" + _mysqlReg.escapeString(serverName) + "' " + " and node_name='" + _mysqlReg.escapeString(nodeName) + "' "; + + _mysqlReg.execute(sSql); + + TLOGDEBUG("CDbHandle::setPatchInfo " << app << "." << serverName << "_" << nodeName << " affected:" << _mysqlReg.getAffectedRows() << endl); + + return 0; + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::setPatchInfo " << app << "." << serverName << "_" << nodeName << " exception: " << ex.what() << endl); + return -1; + } +} + +int CDbHandle::setServerTarsVersion(const string& app, const string& serverName, const string& nodeName, const string& version) +{ + try + { + + int64_t iStart = TNOWMS; + string sSql = "update t_server_conf " + "set tars_version = '" + _mysqlReg.escapeString(version) + "' " + "where application='" + _mysqlReg.escapeString(app) + "' " + " and server_name='" + _mysqlReg.escapeString(serverName) + "' " + " and node_name='" + _mysqlReg.escapeString(nodeName) + "' "; + + _mysqlReg.execute(sSql); + + TLOGDEBUG("CDbHandle::setServerTarsVersion " << app << "." << serverName << "_" << nodeName + << " affected:" << _mysqlReg.getAffectedRows() + << "|cost:" << (TNOWMS - iStart) << endl); + + return 0; + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::setServerTarsVersion " << app << "." << serverName << "_" << nodeName << " exception: " << ex.what() << endl); + return -1; + } +} + +NodePrx CDbHandle::getNodePrx(const string& nodeName) +{ + try + { + TC_ThreadLock::Lock lock(_NodePrxLock); + + if (_mapNodePrxCache.find(nodeName) != _mapNodePrxCache.end()) + { + return _mapNodePrxCache[nodeName]; + } + + string sSql = "select node_obj " + "from t_node_info " + "where node_name='" + _mysqlReg.escapeString(nodeName) + "' and present_state='active'"; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sSql); + TLOGDEBUG("CDbHandle::getNodePrx '" << nodeName << "' affected:" << res.size() << endl); + + if (res.size() == 0) + { + throw Tars("node '" + nodeName + "' not registered or heartbeart timeout,please check for it"); + } + + NodePrx nodePrx; + g_app.getCommunicator()->stringToProxy(res[0]["node_obj"], nodePrx); + + _mapNodePrxCache[nodeName] = nodePrx; + + return nodePrx; + + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::getNodePrx " << nodeName << " exception: " << ex.what() << endl); + throw Tars(string("get node record from db error:") + ex.what()); + } + catch (tars::TarsException& ex) + { + TLOGERROR("CDbHandle::getNodePrx " << nodeName << " exception: " << ex.what() << endl); + throw ex; + } + +} + +int CDbHandle::checkNodeTimeout(unsigned uTimeout) +{ + try + { + //这里先检查下,记录下有哪些节点超时了,方便定位问题 + { + string sTmpSql = "select node_name from t_node_info where last_heartbeat < date_sub(now(), INTERVAL " + tars::TC_Common::tostr(uTimeout) + " SECOND)"; + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sTmpSql); + if (res.size() > 0) + { + TLOGDEBUG( "CDbHandle::checkNodeTimeout affected:" << tars::TC_Common::tostr(res.data()) << endl); + } + } + + int64_t iStart = TNOWMS; + + string sSql = "update t_node_info as node " + " left join t_server_conf as server using (node_name) " + "set node.present_state='inactive', server.present_state='inactive', server.process_id=0 " + "where last_heartbeat < date_sub(now(), INTERVAL " + tars::TC_Common::tostr(uTimeout) + " SECOND)"; + + _mysqlReg.execute(sSql); + + TLOGDEBUG("CDbHandle::checkNodeTimeout (" << uTimeout << "s) affected:" << _mysqlReg.getAffectedRows() << "|cost:" << (TNOWMS - iStart) << endl); + + return _mysqlReg.getAffectedRows(); + + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::checkNodeTimeout exception: " << ex.what() << endl); + return -1; + } + +} + +int CDbHandle::checkRegistryTimeout(unsigned uTimeout) +{ + try + { + string sSql = "update t_registry_info " + "set present_state='inactive' " + "where last_heartbeat < date_sub(now(), INTERVAL " + tars::TC_Common::tostr(uTimeout) + " SECOND)"; + + _mysqlReg.execute(sSql); + + TLOGDEBUG("CDbHandle::checkRegistryTimeout (" << uTimeout << "s) affected:" << _mysqlReg.getAffectedRows() << endl); + + return _mysqlReg.getAffectedRows(); + + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::checkRegistryTimeout exception: " << ex.what() << endl); + return -1; + } + +} + +int CDbHandle::checkSettingState(const int iCheckLeastChangedTime) +{ + try + { + TLOGDEBUG("CDbHandle::checkSettingState ____________________________________" << endl); + + string sSql = "select application, server_name, node_name, setting_state " + "from t_server_conf " + "where setting_state='active' " //检查应当启动的 + "and server_type != 'tars_dns'" //仅用来提供dns服务的除外 + "and registry_timestamp >='" + TC_Common::tm2str(TC_TimeProvider::getInstance()->getNow() - iCheckLeastChangedTime) + "'"; + + int64_t iStart = TNOWMS; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sSql); + + TLOGDEBUG("CDbHandle::checkSettingState setting_state='active' affected:" << res.size() << "|cost:" << (TNOWMS - iStart) << endl); + + NodePrx nodePrx; + for (unsigned i = 0; i < res.size(); i++) + { + string sResult; + TLOGDEBUG("checking [" << i << "]: " << res[i]["application"] << "." << res[i]["server_name"] << "_" << res[i]["node_name"] << endl); + try + { + nodePrx = getNodePrx(res[i]["node_name"]); + if (nodePrx) + { + if (nodePrx->getSettingState(res[i]["application"], res[i]["server_name"], sResult) != Active) + { + string sTempSql = "select application, server_name, node_name, setting_state " + "from t_server_conf " + "where setting_state='active' " + "and application = '" + res[i]["application"] + "' " + "and server_name = '" + res[i]["server_name"] + "' " + "and node_name = '" + res[i]["node_name"] + "'"; + + if (_mysqlReg.queryRecord(sTempSql).size() == 0) + { + TLOGDEBUG(res[i]["application"] << "." << res[i]["server_name"] << "_" << res[i]["node_name"] + << " not setting active,and not need restart" << endl); + continue; + } + + TLOGDEBUG(res[i]["application"] << "." << res[i]["server_name"] << "_" << res[i]["node_name"] << " not setting active, start it" << endl); + + int iRet = nodePrx->startServer(res[i]["application"], res[i]["server_name"], sResult); + + TLOGDEBUG("startServer ret=" << iRet << ",result=" << sResult << endl); + } + } + } + + catch (tars::TarsException& ex) + { + TLOGERROR("checking " << res[i]["application"] << "." << res[i]["server_name"] << "_" << res[i]["node_name"] + << "' exception: " << ex.what() << endl); + } + catch (exception& ex) + { + TLOGERROR("checking " << res[i]["application"] << "." << res[i]["server_name"] << "_" << res[i]["node_name"] << "' exception: " << ex.what() << endl); + } + } + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::checkSettingState exception: " << ex.what() << endl); + return -1; + } + TLOGDEBUG("CDbHandle::checkSettingState ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << endl); + + return 0; +} + +int CDbHandle::getGroupId(const string& ip) +{ + + map& groupIdMap = _groupIdMap.getReaderData(); + map::iterator it = groupIdMap.find(ip); + if (it != groupIdMap.end()) + { + return it->second; + } + + uint32_t uip = stringIpToInt(ip); + string ipStar = Ip2StarStr(uip); + it = groupIdMap.find(ipStar); + if (it != groupIdMap.end()) + { + return it->second; + } + + return -1; +} + +int CDbHandle::getGroupIdByName(const string& sGroupName) +{ + int iGroupId = -1; + try + { + if (sGroupName.empty()) + { + return iGroupId; + } + + map& groupNameMap = _groupNameMap.getReaderData(); + map::iterator it = groupNameMap.find(sGroupName); + if (it != groupNameMap.end()) + { + TLOGINFO("CDbHandle::getGroupIdByName: "<< sGroupName << "|" << it->second << endl); + return it->second; + } + } + catch (exception& ex) + { + TLOGERROR("CDbHandle::getGroupIdByName exception:" << ex.what() << endl); + } + catch (...) + { + TLOGERROR("CDbHandle::getGroupIdByName unknown exception" << endl); + } + + TLOGINFO("CDbHandle::getGroupIdByName " << sGroupName << "|" << endl); + return -1; +} + +int CDbHandle::loadIPPhysicalGroupInfo(bool fromInit) +{ + tars::TC_Mysql::MysqlData res; + try + { + string sSql = "select group_id,ip_order,allow_ip_rule,denny_ip_rule,group_name from t_server_group_rule " + "order by group_id"; + + res = _mysqlReg.queryRecord(sSql); + + TLOGDEBUG("CDbHandle::loadIPPhysicalGroupInfo get server group from db, records affected:" << res.size() << endl); + + load2GroupMap(res.data()); + } + catch (TC_Mysql_Exception& ex) + { + sendSqlErrorAlarmSMS(); + TLOGERROR("CDbHandle::loadIPPhysicalGroupInfo exception: " << ex.what() << endl); + if (fromInit) + { + //初始化是出现异常,退出, 八成是数据库权限问题 + assert(0); + } + } + catch (exception& ex) + { + TLOGDEBUG("CDbHandle::loadIPPhysicalGroupInfo " << ex.what() << endl); + if (fromInit) + { + assert(0); + } + } + return -1; +} + +void CDbHandle::load2GroupMap(const vector >& serverGroupRule) +{ + map& groupIdMap = _groupIdMap.getWriterData(); + map& groupNameMap = _groupNameMap.getWriterData(); + groupIdMap.clear(); //规则改变 清除以前缓存 + groupNameMap.clear(); + vector >::const_iterator it = serverGroupRule.begin(); + for (; it != serverGroupRule.end(); it++) + { + int groupId = TC_Common::strto(it->find("group_id")->second); + vector vIp = TC_Common::sepstr(it->find("allow_ip_rule")->second, "|"); + for (size_t j = 0; j < vIp.size(); j++) + { + groupIdMap[vIp[j]] = groupId; + } + + groupNameMap[it->find("group_name")->second] = groupId; + } + _groupIdMap.swap(); + _groupNameMap.swap(); + +} + + +int CDbHandle::loadGroupPriority(bool fromInit) +{ + std::map & mapPriority = _mapGroupPriority.getWriterData(); + mapPriority.clear(); + try + { + std::string s_command("SELECT id,group_list,station FROM t_group_priority ORDER BY list_order ASC"); + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(s_command); + TLOGDEBUG("CDbHandle::loadGroupPriority load group priority from db, records affected:" << res.size() << endl); + + for (unsigned int i = 0; i < res.size(); i++) + { + mapPriority[i].sGroupID = res[i]["id"]; + mapPriority[i].sStation = res[i]["station"]; + + std::vector vecGroupID = TC_Common::sepstr(res[i]["group_list"], "|,;", false); + std::copy(vecGroupID.begin(), vecGroupID.end(), std::inserter(mapPriority[i].setGroupID, mapPriority[i].setGroupID.begin())); + TLOGDEBUG("loaded groups priority to cache [" << mapPriority[i].sStation << "] group size:" << mapPriority[i].setGroupID.size() << endl); + } + + _mapGroupPriority.swap(); + + TLOGDEBUG("loaded groups priority to cache virtual group size:" << mapPriority.size() << endl); + } + catch (TC_Mysql_Exception& ex) + { + sendSqlErrorAlarmSMS(); + TLOGERROR("CDbHandle::loadGroupPriority exception: " << ex.what() << endl); + if (fromInit) + { + assert(0); + } + return -1; + } + catch (exception& ex) + { + TLOGDEBUG("CDbHandle::loadGroupPriority " << ex.what() << endl); + if (fromInit) + { + assert(0); + } + return -1; + } + + return 0; +} + + +int CDbHandle::computeInactiveRate() +{ + try + { + std::string sCommand("SELECT SUM(CASE present_state WHEN 'active' THEN 1 ELSE 0 END) AS active, " + "SUM(CASE present_state WHEN 'inactive' THEN 1 ELSE 0 END) AS inactive FROM t_node_info;"); + + int64_t iStart = TNOWMS; + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sCommand); + TLOGINFO(__FUNCTION__ << "|cost:" << (TNOWMS - iStart) << endl); + if (res.size() != 1) + { + TLOGDEBUG("loaded inactive rate failed, size(" << res.size() << ") ne 1" << endl); + return -1; + } + + int iActive = TC_Common::strto(res[0]["active"]); + int iInactive = TC_Common::strto(res[0]["inactive"]); + + if (iActive < 0 || iInactive < 0) + { + TLOGDEBUG("loaded inactive rate failed, active(" << iActive << ") inactive(" << iInactive << ")" << endl); + return -2; + } + + return (iInactive + iActive) <= 0 ? 0 : static_cast(iInactive / (iInactive + iActive) * 100); + } + catch (TC_Mysql_Exception& ex) + { + sendSqlErrorAlarmSMS(); + TLOGERROR("CDbHandle::computeInactiveRate exception: " << ex.what() << endl); + return -3; + } + catch (exception& ex) + { + TLOGERROR("CDbHandle::computeInactiveRate " << ex.what() << endl); + return -4; + } +} + +TC_Mysql::MysqlData CDbHandle::UnionRecord(TC_Mysql::MysqlData& data1, TC_Mysql::MysqlData& data2) +{ + TC_Mysql::MysqlData result; + + result.data() = data1.data(); + + vector >& vTmp = data2.data(); + vector >::iterator it = vTmp.begin(); + for (; it != vTmp.end(); it++) + { + result.data().push_back(*it); + } + + return result; +} + +int CDbHandle::loadObjectIdCache(const bool bRecoverProtect, const int iRecoverProtectRate, const int iLoadTimeInterval, const bool bLoadAll, bool fromInit) +{ + ObjectsCache objectsCache; + SetDivisionCache setDivisionCache; + std::map mapStatus; + + try + { + int64_t iStart = TNOWMS; + if (bLoadAll) + { + //加载分组信息一定要在加载服务信息之前 + loadIPPhysicalGroupInfo(fromInit); + //加载城市信息 + loadGroupPriority(fromInit); + } + + //加载存活server及registry列表信息 + string sSql1 = + "select adapter.servant,adapter.endpoint,server.enable_group,server.setting_state,server.present_state,server.application,server.server_name,server.node_name,server.enable_set,server.set_name,server.set_area,server.set_group,server.ip_group_name,server.bak_flag " + "from t_adapter_conf as adapter right join t_server_conf as server using (application, server_name, node_name)"; + + //增量加载逻辑 + if (!bLoadAll) + { + string sInterval = TC_Common::tm2str(TC_TimeProvider::getInstance()->getNow() - iLoadTimeInterval); + sSql1 += " ,(select distinct application,server_name from t_server_conf"; + sSql1 += " where registry_timestamp >='" + sInterval + "'"; + sSql1 += " union select distinct application,server_name from t_adapter_conf"; + sSql1 += " where registry_timestamp >='" + sInterval + "') as tmp"; + sSql1 += " where server.application=tmp.application and server.server_name=tmp.server_name"; + } + + string sSql2 = "select servant, endpoint, enable_group, present_state as setting_state, present_state, tars_version as application, tars_version as server_name, tars_version as node_name,'N' as enable_set,'' as set_name,'' as set_area,'' as set_group ,'' " + "as ip_group_name , '' as bak_flag from t_registry_info order by endpoint"; + + tars::TC_Mysql::MysqlData res; + + { + tars::TC_Mysql::MysqlData res1 = _mysqlReg.queryRecord(sSql1); + + tars::TC_Mysql::MysqlData res2 = _mysqlReg.queryRecord(sSql2); + TLOGDEBUG("CDbHandle::loadObjectIdCache load " << (bLoadAll ? "all " : "") << "Active objects from db, records affected:" << (res1.size() + res2.size()) + << "|cost:" << (TNOWMS - iStart) << endl); + iStart = TNOWMS; + res = UnionRecord(res1, res2); + } + for (unsigned i = 0; i < res.size(); i++) + { + try + { + if (res[i]["servant"].empty() && res[i]["endpoint"].empty()) + { + TLOGDEBUG(res[i]["application"] << "-" << res[i]["server_name"] << "-" << res[i]["node_name"] << " NULL" << endl); + ServantStatusKey statusKey = { res[i]["application"], res[i]["server_name"], res[i]["node_name"] }; + mapStatus[statusKey] = (res[i]["setting_state"] == "active" && res[i]["present_state"] == "active") ? tars::Active : tars::Inactive; + continue; + } + + TC_Endpoint ep; + try + { + ep.parse(res[i]["endpoint"]); + } + catch (exception& ex) + { + TLOGERROR("CDbHandle::loadObjectIdCache " << ex.what() << endl); + continue; + } + + EndpointF epf; + epf.host = ep.getHost(); + epf.port = ep.getPort(); + epf.timeout = ep.getTimeout(); + + // 现在支持三种类型:0 UDP, 1 TCP, 2 SSL + // 所以istcp字段作为int类型使用 + if (!ep.isTcp()) + { + epf.istcp = EndpointInfo::UDP; + } + else + { + if (ep.isSSL()) + epf.istcp = EndpointInfo::SSL; + else + epf.istcp = EndpointInfo::TCP; + } + + epf.authType = ep.getAuthType(); + epf.grouprealid = getGroupId(epf.host); + string ip_group_name = res[i]["ip_group_name"]; + epf.grouprealid = ip_group_name.empty() ? getGroupId(epf.host) : getGroupIdByName(ip_group_name); + epf.groupworkid = TC_Common::lower(res[i]["enable_group"]) == "y" ? epf.grouprealid : -1; + if (TC_Common::lower(res[i]["enable_group"]) == "y" && epf.grouprealid == -1) + { + //记录查不到分组的组名和ip + FDLOG("group_id") << ip_group_name << "|" << epf.host << endl; + } + + epf.setId = ""; + epf.bakFlag = TC_Common::strto(res[i]["bak_flag"]); + + bool bSet = TC_Common::lower(res[i]["enable_set"]) == "y"; + if (bSet) + { + epf.setId = res[i]["set_name"] + "." + res[i]["set_area"] + "." + res[i]["set_group"]; + } + + TLOGDEBUG("CDbHandle::loadObjectIdCache :" << res[i]["servant"] << "." << epf.host << "|" << epf.grouprealid << "|" << epf.groupworkid << "|" << res[i]["setting_state"] << "|" << res[i]["present_state"] << endl); + + bool bActive = true; + + ServantStatusKey statusKey = { res[i]["application"], res[i]["server_name"], res[i]["node_name"] }; + + if ((res[i]["setting_state"] == "active" && res[i]["present_state"] == "active") + || res[i]["servant"] == "tars.tarsAdminRegistry.AdminRegObj") //如果是管理服务, 强制认为它是活的 + { + //存活列表 + objectsCache[res[i]["servant"]].vActiveEndpoints.push_back(epf); + mapStatus[statusKey] = tars::Active; + } + else + { + //非存活列表 + objectsCache[res[i]["servant"]].vInactiveEndpoints.push_back(epf); + mapStatus[statusKey] = tars::Inactive; + bActive = false; + } + + if (bSet) + { + if (res[i]["set_name"].empty() || res[i]["set_area"].empty() || res[i]["set_group"].empty() || res[i]["set_name"] == "*" || res[i]["set_area"] == "*") + { + TLOGERROR("CDbHandle::loadObjectIdCache: " << res[i]["servant"] << "." << epf.host << "|set division invalid[" << res[i]["set_name"] << "." << res[i]["set_area"] << "." << res[i]["set_group"] << "]" << endl); + bSet = false; + } + } + + //set划分信息 + if (bSet) + { + //set区域 + string sSetArea = res[i]["set_name"] + "." + res[i]["set_area"]; + //set全称 + string sSetId = res[i]["set_name"] + "." + res[i]["set_area"] + "." + res[i]["set_group"]; + + SetServerInfo setServerInfo; + setServerInfo.bActive = bActive; + setServerInfo.epf = epf; + + setServerInfo.sSetId = sSetId; + setServerInfo.sSetArea = sSetArea; + + setDivisionCache[res[i]["servant"]][res[i]["set_name"]].push_back(setServerInfo); + TLOGINFO("CDbHandle::loadObjectIdCache " << res[i]["servant"] << "." << epf.host << "|" << sSetId << "|" << setServerInfo.bActive << endl); + } + else if (!bLoadAll) + { + //增量加载,如果不启用set也要赋个空值,防止更新缓存时不彻底 + map > mTemp = setDivisionCache[res[i]["servant"]]; + setDivisionCache[res[i]["servant"]] = mTemp; + } + } + catch (TC_EndpointParse_Exception& ex) + { + TLOGERROR("CDbHandle::loadObjectIdCache " << ex.what() << endl); + } + } + + //替换到cache + int iRate = bRecoverProtect == true ? computeInactiveRate() : 0; + if (bRecoverProtect == true && iRate > iRecoverProtectRate && objectsCache.size() > 0) + { + TLOGDEBUG("CDbHandle::loadObjectIdCache now database recover protect valid, rate:" << iRate << ",iRecoverProtectRate:" << iRecoverProtectRate + << std::boolalpha << ",bRecoverProtect:" << bRecoverProtect << endl); + return -1; + } + + updateObjectsCache(objectsCache, bLoadAll); + updateStatusCache(mapStatus, bLoadAll); + updateDivisionCache(setDivisionCache, bLoadAll); + + TLOGDEBUG("loaded objects to cache size:" << objectsCache.size() << endl); + TLOGDEBUG("loaded server status to cache size:" << mapStatus.size() << endl); + TLOGDEBUG("loaded set server to cache size:" << setDivisionCache.size() << endl); + FDLOG() << "loaded objects to cache size:" << objectsCache.size() << endl; + FDLOG() << "loaded set server to cache size:" << setDivisionCache.size() << endl; + + TLOGDEBUG("CDbHandle::loadObjectIdCache parse " << (bLoadAll ? "all " : "") << "|cost:" << (TNOWMS - iStart) << endl); + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::loadObjectIdCache exception: " << ex.what() << endl); + + sendSqlErrorAlarmSMS(); + if (fromInit) + { + //初始化是出现异常,退出 + assert(0); + } + return -1; + } + catch (exception& ex) + { + TLOGDEBUG("CDbHandle::loadObjectIdCache " << ex.what() << endl); + if (fromInit) + { + //初始化是出现异常,退出 + assert(0); + } + return -1; + } + + return 0; +} + +int CDbHandle::updateRegistryInfo2Db(bool bRegHeartbeatOff) +{ + if (bRegHeartbeatOff) + { + TLOGDEBUG("updateRegistryInfo2Db not need to update reigstry status !" << endl); + return 0; + } + + map::iterator iter; + map mapServantEndpoint = g_app.getServantEndpoint(); + if (mapServantEndpoint.size() == 0) + { + TLOGERROR("fatal error, get registry servant failed!" << endl); + return -1; + } + + try + { + string sSql = "replace into t_registry_info (locator_id, servant, endpoint, last_heartbeat, present_state, tars_version) " + "values "; + + TC_Endpoint locator; + locator.parse(mapServantEndpoint[(*g_pconf)["/tars/objname"]]); + + for (iter = mapServantEndpoint.begin(); iter != mapServantEndpoint.end(); iter++) + { + sSql += (iter == mapServantEndpoint.begin() ? string("") : string(", ")) + + "('" + locator.getHost() + ":" + TC_Common::tostr(locator.getPort()) + "', " + "'" + iter->first + "', '" + iter->second + "', now(), 'active', " + + "'" + _mysqlReg.escapeString(TARS_VERSION) + "')"; + } + _mysqlReg.execute(sSql); + TLOGDEBUG("CDbHandle::updateRegistryInfo2Db affected:" << _mysqlReg.getAffectedRows() << endl); + } + catch (TC_Mysql_Exception& ex) + { + sendSqlErrorAlarmSMS(); + TLOGERROR("CDbHandle::updateRegistryInfo2Db exception: " << ex.what() << endl); + return -1; + } + catch (exception& ex) + { + TLOGERROR("CDbHandle::updateRegistryInfo2Db exception: " << ex.what() << endl); + return -1; + } + + return 0; +} + +vector CDbHandle::findObjectById(const string& id) +{ + ObjectsCache::iterator it; + ObjectsCache& usingCache = _objectsCache.getReaderData(); + + if ((it = usingCache.find(id)) != usingCache.end()) + { + return it->second.vActiveEndpoints; + } + else + { + vector activeEp; + return activeEp; + } +} + + +int CDbHandle::findObjectById4All(const string& id, vector& activeEp, vector& inactiveEp) +{ + + TLOGDEBUG(__FUNCTION__ << " id: " << id << endl); + + ObjectsCache::iterator it; + ObjectsCache& usingCache = _objectsCache.getReaderData(); + + if ((it = usingCache.find(id)) != usingCache.end()) + { + activeEp = it->second.vActiveEndpoints; + inactiveEp = it->second.vInactiveEndpoints; + } + else + { + activeEp.clear(); + inactiveEp.clear(); + } + + return 0; +} + +vector CDbHandle::getEpsByGroupId(const vector& vecEps, const GroupUseSelect GroupSelect, int iGroupId, ostringstream& os) +{ + os << "|"; + vector vResult; + + for (unsigned i = 0; i < vecEps.size(); i++) + { + os << vecEps[i].host << ":" << vecEps[i].port << "(" << vecEps[i].groupworkid << ");"; + if (GroupSelect == ENUM_USE_WORK_GROUPID && vecEps[i].groupworkid == iGroupId) + { + vResult.push_back(vecEps[i]); + } + if (GroupSelect == ENUM_USE_REAL_GROUPID && vecEps[i].grouprealid == iGroupId) + { + vResult.push_back(vecEps[i]); + } + } + + return vResult; +} + +vector CDbHandle::getEpsByGroupId(const vector& vecEps, const GroupUseSelect GroupSelect, const set& setGroupID, ostringstream& os) +{ + os << "|"; + std::vector vecResult; + + for (std::vector::size_type i = 0; i < vecEps.size(); i++) + { + os << vecEps[i].host << ":" << vecEps[i].port << "(" << vecEps[i].groupworkid << ")"; + if (GroupSelect == ENUM_USE_WORK_GROUPID && setGroupID.count(vecEps[i].groupworkid) == 1) + { + vecResult.push_back(vecEps[i]); + } + if (GroupSelect == ENUM_USE_REAL_GROUPID && setGroupID.count(vecEps[i].grouprealid) == 1) + { + vecResult.push_back(vecEps[i]); + } + } + + return vecResult; +} + +int CDbHandle::findObjectByIdInSameGroup(const string& id, const string& ip, vector& activeEp, vector& inactiveEp, ostringstream& os) +{ + activeEp.clear(); + inactiveEp.clear(); + + int iClientGroupId = getGroupId(ip); + + os << "|(" << iClientGroupId << ")"; + + if (iClientGroupId == -1) + { + return findObjectById4All(id, activeEp, inactiveEp); + } + + ObjectsCache::iterator it; + ObjectsCache& usingCache = _objectsCache.getReaderData(); + + if ((it = usingCache.find(id)) != usingCache.end()) + { + activeEp = getEpsByGroupId(it->second.vActiveEndpoints, ENUM_USE_WORK_GROUPID, iClientGroupId, os); + inactiveEp = getEpsByGroupId(it->second.vInactiveEndpoints, ENUM_USE_WORK_GROUPID, iClientGroupId, os); + + if (activeEp.size() == 0) //没有同组的endpoit,匹配未启用分组的服务 + { + activeEp = getEpsByGroupId(it->second.vActiveEndpoints, ENUM_USE_WORK_GROUPID, -1, os); + inactiveEp = getEpsByGroupId(it->second.vInactiveEndpoints, ENUM_USE_WORK_GROUPID, -1, os); + } + if (activeEp.size() == 0) //没有同组的endpoit + { + activeEp = it->second.vActiveEndpoints; + inactiveEp = it->second.vInactiveEndpoints; + } + } + + return 0; +} + +int CDbHandle::findObjectByIdInGroupPriority(const std::string& sID, const std::string& sIP, std::vector& vecActive, std::vector& vecInactive, std::ostringstream& os) +{ + vecActive.clear(); + vecInactive.clear(); + + int iClientGroupID = getGroupId(sIP); + os << "|(" << iClientGroupID << ")"; + if (iClientGroupID == -1) + { + return findObjectById4All(sID, vecActive, vecInactive); + } + + ObjectsCache& usingCache = _objectsCache.getReaderData(); + ObjectsCache::iterator itObject = usingCache.find(sID); + if (itObject == usingCache.end()) return 0; + + //首先在同组中查找 + { + vecActive = getEpsByGroupId(itObject->second.vActiveEndpoints, ENUM_USE_WORK_GROUPID, iClientGroupID, os); + vecInactive = getEpsByGroupId(itObject->second.vInactiveEndpoints, ENUM_USE_WORK_GROUPID, iClientGroupID, os); + os << "|(In Same Group: " << iClientGroupID << " Active=" << vecActive.size() << " Inactive=" << vecInactive.size() << ")"; + } + + //启用分组,但同组中没有找到,在优先级序列中查找 + std::map & mapPriority = _mapGroupPriority.getReaderData(); + for (std::map::iterator it = mapPriority.begin(); it != mapPriority.end() && vecActive.empty(); it++) + { + if (it->second.setGroupID.count(iClientGroupID) == 0) + { + os << "|(Not In Priority " << it->second.sGroupID << ")"; + continue; + } + vecActive = getEpsByGroupId(itObject->second.vActiveEndpoints, ENUM_USE_WORK_GROUPID, it->second.setGroupID, os); + vecInactive = getEpsByGroupId(itObject->second.vInactiveEndpoints, ENUM_USE_WORK_GROUPID, it->second.setGroupID, os); + os << "|(In Priority: " << it->second.sGroupID << " Active=" << vecActive.size() << " Inactive=" << vecInactive.size() << ")"; + } + + //没有同组的endpoit,匹配未启用分组的服务 + if (vecActive.empty()) + { + vecActive = getEpsByGroupId(itObject->second.vActiveEndpoints, ENUM_USE_WORK_GROUPID, -1, os); + vecInactive = getEpsByGroupId(itObject->second.vInactiveEndpoints, ENUM_USE_WORK_GROUPID, -1, os); + os << "|(In No Grouop: Active=" << vecActive.size() << " Inactive=" << vecInactive.size() << ")"; + } + + //在未分组的情况下也没有找到,返回全部地址(此时基本上所有的服务都已挂掉) + if (vecActive.empty()) + { + vecActive = itObject->second.vActiveEndpoints; + vecInactive = itObject->second.vInactiveEndpoints; + os << "|(In All: Active=" << vecActive.size() << " Inactive=" << vecInactive.size() << ")"; + } + + return 0; +} + +int CDbHandle::findObjectByIdInSameStation(const std::string& sID, const std::string& sStation, std::vector& vecActive, std::vector& vecInactive, std::ostringstream& os) +{ + vecActive.clear(); + vecInactive.clear(); + + //获得station所有组 + std::map & mapPriority = _mapGroupPriority.getReaderData(); + std::map::iterator itGroup = mapPriority.end(); + for (itGroup = mapPriority.begin(); itGroup != mapPriority.end(); itGroup++) + { + if (itGroup->second.sStation != sStation) continue; + + break; + } + + if (itGroup == mapPriority.end()) + { + os << "|not found station:" << sStation; + return -1; + } + + ObjectsCache& usingCache = _objectsCache.getReaderData(); + ObjectsCache::iterator itObject = usingCache.find(sID); + if (itObject == usingCache.end()) return 0; + + //查找对应所有组下的IP地址 + vecActive = getEpsByGroupId(itObject->second.vActiveEndpoints, ENUM_USE_REAL_GROUPID, itGroup->second.setGroupID, os); + vecInactive = getEpsByGroupId(itObject->second.vInactiveEndpoints, ENUM_USE_REAL_GROUPID, itGroup->second.setGroupID, os); + + return 0; +} + +int CDbHandle::findObjectByIdInSameSet(const string& sID, const vector& vtSetInfo, std::vector& vecActive, std::vector& vecInactive, std::ostringstream& os) +{ + string sSetName = vtSetInfo[0]; + string sSetArea = vtSetInfo[0] + "." + vtSetInfo[1]; + string sSetId = vtSetInfo[0] + "." + vtSetInfo[1] + "." + vtSetInfo[2]; + + SetDivisionCache& usingSetDivisionCache = _setDivisionCache.getReaderData(); + SetDivisionCache::iterator it = usingSetDivisionCache.find(sID); + if (it == usingSetDivisionCache.end()) + { + //此情况下没启动set + TLOGINFO("CDbHandle::findObjectByIdInSameSet:" << __LINE__ << "|" << sID << " haven't start set|" << sSetId << endl); + return -1; + } + + map >::iterator setNameIt = it->second.find(sSetName); + if (setNameIt == (it->second).end()) + { + //此情况下没启动set + TLOGINFO("CDbHandle::findObjectByIdInSameSet:" << __LINE__ << "|" << sID << " haven't start set|" << sSetId << endl); + return -1; + } + + if (vtSetInfo[2] == "*") + { + //检索通配组和set组中的所有服务 + vector vServerInfo = setNameIt->second; + for (size_t i = 0; i < vServerInfo.size(); i++) + { + if (vServerInfo[i].sSetArea == sSetArea) + { + if (vServerInfo[i].bActive) + { + vecActive.push_back(vServerInfo[i].epf); + } + else + { + vecInactive.push_back(vServerInfo[i].epf); + } + } + } + + return (vecActive.empty() && vecInactive.empty()) ? -2 : 0; + } + else + { + + // 1.从指定set组中查找 + int iRet = findObjectByIdInSameSet(sSetId, setNameIt->second, vecActive, vecInactive, os); + if (iRet != 0 && vtSetInfo[2] != "*") + { + // 2. 步骤1中没找到,在通配组里找 + string sWildSetId = vtSetInfo[0] + "." + vtSetInfo[1] + ".*"; + iRet = findObjectByIdInSameSet(sWildSetId, setNameIt->second, vecActive, vecInactive, os); + } + + return iRet; + } + + +} + +int CDbHandle::findObjectByIdInSameSet(const string& sSetId, const vector& vSetServerInfo, std::vector& vecActive, std::vector& vecInactive, std::ostringstream& os) +{ + for (size_t i = 0; i < vSetServerInfo.size(); ++i) + { + if (vSetServerInfo[i].sSetId == sSetId) + { + if (vSetServerInfo[i].bActive) + { + vecActive.push_back(vSetServerInfo[i].epf); + } + else + { + vecInactive.push_back(vSetServerInfo[i].epf); + } + } + } + + int iRet = (vecActive.empty() && vecInactive.empty()) ? -2 : 0; + return iRet; +} +int CDbHandle::getNodeTemplateName(const string nodeName, string& sTemplateName) +{ + try + { + string sSql = + "select template_name " + "from t_node_info " + "where node_name='" + _mysqlReg.escapeString(nodeName) + "'"; + + tars::TC_Mysql::MysqlData res = _mysqlReg.queryRecord(sSql); + + if (res.size() != 0) + { + sTemplateName = res[0]["template_name"]; + } + + TLOGDEBUG("CDbHandle::getNodeTemplateName '" << nodeName << "' affected:" << res.size() + << " get template_name:'" << sTemplateName << "'" << endl); + + return 0; + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("CDbHandle::getNodeTemplateName exception: " << ex.what() << endl); + return -1; + } + + return 0; +} + +void CDbHandle::updateStatusCache(const std::map& mStatus, bool updateAll) +{ + TC_ThreadLock::Lock lock(_mapServantStatusLock); + if (updateAll) + { + //全量更新 + _mapServantStatus = mStatus; + } + else + { + std::map::const_iterator it = mStatus.begin(); + for (; it != mStatus.end(); it++) + { + _mapServantStatus[it->first] = it->second; + } + } +} + +void CDbHandle::updateObjectsCache(const ObjectsCache& objCache, bool updateAll) +{ + //全量更新 + if (updateAll) + { + _objectsCache.getWriterData() = objCache; + _objectsCache.swap(); + } + else + { + //用查询数据覆盖一下 + _objectsCache.getWriterData() = _objectsCache.getReaderData(); + ObjectsCache& tmpObjCache = _objectsCache.getWriterData(); + + ObjectsCache::const_iterator it = objCache.begin(); + for (; it != objCache.end(); it++) + { + //增量的时候加载的是服务的所有节点,因此这里直接替换 + tmpObjCache[it->first] = it->second; + } + _objectsCache.swap(); + } +} + +void CDbHandle::updateDivisionCache(const SetDivisionCache& setDivisionCache, bool updateAll) +{ + //全量更新 + if (updateAll) + { + _setDivisionCache.getWriterData() = setDivisionCache; + _setDivisionCache.swap(); + } + else + { + _setDivisionCache.getWriterData() = _setDivisionCache.getReaderData(); + SetDivisionCache& tmpsetCache = _setDivisionCache.getWriterData(); + SetDivisionCache::const_iterator it = setDivisionCache.begin(); + for (; it != setDivisionCache.end(); it++) + { + //有set信息才更新 + if (it->second.size() > 0) + { + tmpsetCache[it->first] = it->second; + } + else if (tmpsetCache.count(it->first)) + { + //这个服务的所有节点都没有启用set,删除缓存中的set信息 + tmpsetCache.erase(it->first); + } + } + _setDivisionCache.swap(); + } +} +void CDbHandle::sendSqlErrorAlarmSMS() +{ + string errInfo = " ERROR:" + g_app.getAdapterEndpoint("QueryAdapter").getHost() + ":主控访问数据库异常,请及时处理"; + TARS_NOTIFY_ERROR(errInfo); + + TLOGERROR("TARS_NOTIFY_ERROR " << errInfo << endl); +} + +uint32_t CDbHandle::stringIpToInt(const std::string& sip) +{ + string ip1, ip2, ip3, ip4; + uint32_t dip, p1, p2, p3; + dip = 0; + p1 = sip.find('.'); + p2 = sip.find('.', p1 + 1); + p3 = sip.find('.', p2 + 1); + ip1 = sip.substr(0, p1); + ip2 = sip.substr(p1 + 1, p2 - p1 - 1); + ip3 = sip.substr(p2 + 1, p3 - p2 - 1); + ip4 = sip.substr(p3 + 1, sip.size() - p3 - 1); + (((unsigned char *)&dip)[0]) = TC_Common::strto(ip1); + (((unsigned char *)&dip)[1]) = TC_Common::strto(ip2); + (((unsigned char *)&dip)[2]) = TC_Common::strto(ip3); + (((unsigned char *)&dip)[3]) = TC_Common::strto(ip4); + return htonl(dip); +} + +string CDbHandle::Ip2Str(uint32_t ip) +{ + char str[50]; + unsigned char *p = (unsigned char *)&ip; + sprintf(str, "%u.%u.%u.%u", p[3], p[2], p[1], p[0]); + return string(str); +} + +string CDbHandle::Ip2StarStr(uint32_t ip) +{ + char str[50]; + unsigned char *p = (unsigned char *)&ip; + sprintf(str, "%u.%u.%u.*", p[3], p[2], p[1]); + return string(str); +} diff --git a/RegistryServer/DbHandle.h b/RegistryServer/DbHandle.h new file mode 100644 index 00000000..8c1e8283 --- /dev/null +++ b/RegistryServer/DbHandle.h @@ -0,0 +1,532 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __DB_HANDLE_H__ +#define __DB_HANDLE_H__ + +#include "util/tc_common.h" +#include "util/tc_config.h" +#include "util/tc_monitor.h" +#include "util/tc_mysql.h" +#include "util/tc_file.h" +#include "jmem/jmem_hashmap.h" +#include "util/tc_readers_writer_data.h" +#include + +#include "Registry.h" +#include "Node.h" +#include "servant/TarsLogger.h" + +#define GROUPCACHEFILE "serverGroupCache.dat" +#define GROUPPROICACHEFILE "GroupPrioCache.dat" + +using namespace tars; +////////////////////////////////////////////////////// + +// +typedef map ObjectsCache; +typedef TarsHashMap FileHashMap; + +//_mapServantStatus的key +struct ServantStatusKey +{ + string application; + string serverName; + string nodeName; +}; + +inline bool operator<(const ServantStatusKey&l, const ServantStatusKey&r) +{ + if(l.application != r.application) return (l.application < r.application); + if(l.serverName != r.serverName) return (l.serverName < r.serverName); + if(l.nodeName != r.nodeName) return (l.nodeName < r.nodeName); + return false; +} + +////////////////////////////////////////////////////// +/** + * 主控获取node信息异常 + */ +struct Tars : public TarsException +{ + Tars(const string &buffer) : TarsException(buffer){}; + Tars(const string &buffer, int err) : TarsException(buffer, err){}; + ~Tars() throw(){}; +}; + +////////////////////////////////////////////////////// +/** + * 数据库操作类 + */ +class CDbHandle +{ +private: + struct GroupPriorityEntry + { + std::string sGroupID; + std::string sStation; + std::set setGroupID; + }; + + enum GroupUseSelect + { + ENUM_USE_WORK_GROUPID, + ENUM_USE_REAL_GROUPID + }; + + //set中服务的信息 + struct SetServerInfo + { + string sSetId; + string sSetArea; + bool bActive; + EndpointF epf; + }; + + // + typedef map > > SetDivisionCache; + +public: + /** + * 构造函数 + */ + CDbHandle() + : _enMultiSql(false) + { + } + + /** + * 初始化 + * @param pconf 配置文件 + * @return 0-成功 others-失败 + */ + int init(TC_Config *pconf); + + /** + * 获取特定node id的对象代理 + * @param nodeName : node id + * @return : 对象代理的智能指针 + */ + NodePrx getNodePrx(const string & nodeName); + + /** + * 保存node注册的session + * @param name node名称 + * @param ni node详细信息 + * @param li node机器负载信息 + * @return 注册是否成功 + */ + int registerNode(const string & name, const NodeInfo & ni, const LoadInfo & li); + + /** + * 更新node的状态为inactive + * + * @param name node名称 + * + * @return 0-成功 others-失败 + */ + int destroyNode(const string & name); + + /** + * 更新node心跳时间及机器负载 + * + * @param name node名称 + * @param load node机器负载信息 + * @return 0-成功 others-失败 + */ + int keepAlive(const string & name, const LoadInfo & li); + + /** + * 获取活动node列表endpoint信息 + * @param out result 结果描述 + * @return map : 对应id node的obj + */ + map getActiveNodeList(string & result); + + /** + * 获取node版本 + * @param name node名称 + * @param version node版本 + * @param out result 结果描述 + * @return 0-成功 others-失败 + */ + int getNodeVersion(const string &nodeName, string &version, string & result); + + /** + * 获取在该node部署的server列表 + * + * @param app: 应用 + * @param serverName: server 名 + * @param nodeName : node id + * + * @return server信息列表 + */ + vector getServers(const string & app, const string & serverName, const string & nodeName, bool withDnsServer = false); + + /** + * 获取server的配置模板 + * @param sTemplateName 模板名称 + * @param sResultDesc 结果描述 + * @return 模板内容 + */ + string getProfileTemplate(const string & sTemplateName, string & sResultDesc); + +protected: + /** + * 获取server的配置模板 + * @param sTemplateName 模板名称 + * @param mapRecursion 被递归到的模板 + * @param sResultDesc 结果描述 + * @return 模板内容 + */ + string getProfileTemplate(const string & sTemplateName, map & mapRecursion, string & sResultDesc); + +public: + /** + * 更新server状态 + * + * @param app: 应用 + * @param serverName: server 名 + * @param nodeName : node id + * @param stateFields: 更新状态字段名 + * @param state : server状态 + * + * @return server信息列表 + */ + int updateServerState(const string & app, const string & serverName, const string & nodeName, const string & stateFields, tars::ServerState state, int processId = -1); + + /** + * 量批更新server状态 + * + * @param vecStateInfo: 批量server的状态 + * + * @return server信息列表 + */ + int updateServerStateBatch(const std::vector & vecStateInfo); + + /** 根据id获取对象 + * + * @param id 对象名称 + * + * @return 返回所有该对象的活动endpoint列表 + */ + vector findObjectById(const string & id); + + /** 根据id获取对象 + * + * @param id 对象名称 + * @out param activeEp 存活的列表 + * @out param inactiveEp 非存活的列表 + * + * @return 0-成功 others-失败 + */ + int findObjectById4All(const string & id, vector& activeEp, vector& inactiveEp); + + /** 根据id获取同组对象 + * + * @param id 对象名称 + * @param ip + * @out param activeEp 存活的列表 + * @out param inactiveEp 非存活的列表 + * @out param os 打印日志使用 + * + * @return 0-成功 others-失败 + */ + int findObjectByIdInSameGroup(const string & id, const string & ip, vector& activeEp, vector& inactiveEp, ostringstream &os); + + /** 根据id获取优先级序列中的对象 + * + * @param id 对象名称 + * @param ip + * @out param vecActive 存活的列表 + * @out param vecInactive 非存活的列表 + * @out param os 打印日志使用 + * + * @return 0-成功 others-失败 + */ + int findObjectByIdInGroupPriority(const std::string &sID, const std::string &sIP, std::vector & vecActive, std::vector & vecInactive, std::ostringstream & os); + + /** 根据id和归属地获取全部对象 + * + * @param id 对象名称 + * @param sStation 归属地 + * @out param vecActive 存活的列表 + * @out param vecInactive 非存活的列表 + * @out param os 打印日志使用 + * + * @return 0-成功 others-失败 + */ + int findObjectByIdInSameStation(const std::string &sID, const std::string & sStation, std::vector & vecActive, std::vector & vecInactive, std::ostringstream & os); + + /** 根据id和set信息获取全部对象 + * + * @param sID 对象名称 + * @param vtSetInfo set信息 + * @out param vecActive 存活的列表 + * @out param vecInactive 非存活的列表 + * @out param os 打印日志使用 + * + * @return 0-成功 others-失败 + */ + int findObjectByIdInSameSet(const string &sID, const vector &vtSetInfo, std::vector & vecActive, std::vector & vecInactive, std::ostringstream & os); + + /** 根据setId获取全部对象 + * + * @param sSetId set名称 + * @param vSetServerInfo SetName下部署的服务信息 + * @out param vecActive 存活的列表 + * @out param vecInactive 非存活的列表 + * @out param os 打印日志使用 + * + * @return 0-成功 others-失败 + */ + int findObjectByIdInSameSet(const string &sSetId, const vector& vSetServerInfo, std::vector & vecActive, std::vector & vecInactive, std::ostringstream & os); + + /** + * 获取application列表 + * @param null + * @param out reuslt + * @return application列表 + */ + vector getAllApplicationNames(string & result); + + /** + * 获取server列表 + * @param null + * @return node 列表 + */ + vector > getAllServerIds(string & result); + + /** + * 获取合并的配置文件 + * @param appServerName + * @param fileName + * @param host + * @param config + * @param resultDesc + * + * @return int + */ + int getConfig(const string &appServerName, const string &fileName, const string &host, string &config, std::string &resultDesc); + + /** + * 设置server发布版本 + * @param app: 应用 + * @param serverName: server 名 + * @param nodeName : node id + * @param version : server 版本 + * @param user : 发布者 + */ + int setPatchInfo(const string & app, const string & serverName, const string & nodeName, const string & version, const string & user); + + /** + * 设置server的tars库版本 + * @param app: 应用 + * @param serverName: server 名 + * @param nodeName : node id + * @param version: server基于的tars版本号 + * + * @return 0-成功 others-失败 + */ + int setServerTarsVersion(const string & app, const string & serverName, const string & nodeName, const string & version); + + /** + * 轮询数据库,将心跳超时的节点及server状态设为不存活 + * @param iTiemout 超时时间 + * @return + */ + int checkNodeTimeout(unsigned uTimeout); + + /** + * 轮询数据库,将心跳超时的registry设为不存活 + * @param iTiemout 超时时间 + * @return + */ + int checkRegistryTimeout(unsigned uTimeout); + + /** + * 定时检查在数据库的设置状态为“active”的服务在Node节点上的状态: + * 如果服务在Node的设置状态不是“active”,则通知Node主动重启该服务 + * + * @param iCheckTimeInterval 每次轮询最近更新的记录,单位为秒 + * @return + */ + int checkSettingState(const int iCheckLeastChangedTime=3600); + + /** + * 在加载对象列表之前,计算当前非活动状态的node的比率 + * @param NULL + * @return + */ + int computeInactiveRate(); + + /** + * 加载对象列表到内存 + * @param bRecoverProtect + * @param iRecoverProtectRate + * @param iLoadTimeInterval 加载最近iLoadTimeInterval秒内变化的记录 + * @param bLoadAll 是否加载所有服务 + * @param bFirstLoad 是否是第一次全量加载 + * @param fromInit 是否来着初始化的调用 + * @return + */ + int loadObjectIdCache(const bool bRecoverProtect, const int iRecoverProtectRate, const int iLoadTimeInterval=60, const bool bLoadAll=false, bool fromInit = false); + + /** + * 加载组优先级到内存 + * @param NULL + * @return + */ + int loadGroupPriority(bool fromInit); + + /** + * 更新registry信息到db + */ + int updateRegistryInfo2Db(bool bRegHeartbeatOff=false); + + /** + * 获取对应node的模板名称 + */ + int getNodeTemplateName(const string nodeName, string & sTemplateName); + + /** + * 根据ip获取组id + * @return int <0 失败 其它正常 + */ + int getGroupId(const string& ip); + + /** + * 根据组名获取组id + * @return int <0 失败 其它正常 + */ + int getGroupIdByName(const string& sGroupName); + + /** + * 加载IP物理分组信息 + */ + int loadIPPhysicalGroupInfo(bool fromInit); + + /** + * ip转换 + */ + static uint32_t stringIpToInt(const std::string& sip); + + /** + * ip转换 + */ + static string Ip2Str(uint32_t ip); + + /** + * ip转换 + */ + static string Ip2StarStr(uint32_t ip); + +protected: + + /** + * 根据group id获取Endpoint + */ + vector getEpsByGroupId(const vector & vecEps, const GroupUseSelect GroupSelect, int iGroupId, ostringstream &os); + + vector getEpsByGroupId(const vector & vecEps, const GroupUseSelect GroupSelect, const set & setGroupID, ostringstream & os); + + /** + * updateServerStateBatch的底层实现函数 + */ + int doUpdateServerStateBatch(const std::vector & vecStateInfo, const size_t sizeBegin, const size_t sizeEnd); + +private: + /** + * 更新缓存中的服务状态值 + * + * @param mStatus + * @param updateAll 是否全部更新 + * @param bFirstLoad 是否是第一次全量加载 + */ + void updateStatusCache(const std::map& mStatus,bool updateAll=false); + + /** + * 更新缓存中的服务信息 + * + * @param objCache + * @param updateAll 是否全部更新 + * @param bFirstLoad 是否是第一次全量加载 + */ + void updateObjectsCache(const ObjectsCache& objCache,bool updateAll=false); + + /** + * 更新缓存中的set信息 + * + * @param objCache + * @param updateAll 是否全部更新 + * @param bFirstLoad 是否是第一次全量加载 + */ + void updateDivisionCache(const SetDivisionCache& setDivisionCache,bool updateAll=false); + + /** + * 对数据库查询结果执行联合操作 + * + * @param data1 + * @param data2 + * + * @return 联合的结果 + */ + TC_Mysql::MysqlData UnionRecord(TC_Mysql::MysqlData& data1,TC_Mysql::MysqlData& data2); + + /** + * 数据库访问异常上报 + */ + void sendSqlErrorAlarmSMS(); + + /** + * 建立ip分组map + */ + void load2GroupMap(const vector >& serverGroupRule); + +protected: + + //是否允许采用多条语句同时执行方式 + bool _enMultiSql; + + //mysql连接对象 + tars::TC_Mysql _mysqlReg; + + //node节点代理列表 + static map _mapNodePrxCache; + static TC_ThreadLock _NodePrxLock; + + //对象列表缓存 + static TC_ReadersWriterData _objectsCache; + + //set划分缓存 + static TC_ReadersWriterData _setDivisionCache; + + //优先级的序列 + static TC_ReadersWriterData > _mapGroupPriority; + + //servant状态表 + static std::map _mapServantStatus; + + //存在多线程更新_mapServantStatus,需要加锁 + static TC_ThreadLock _mapServantStatusLock; + + //分组信息 + static TC_ReadersWriterData > _groupIdMap; + static TC_ReadersWriterData > _groupNameMap; + +}; + +#endif diff --git a/RegistryServer/QueryImp.cpp b/RegistryServer/QueryImp.cpp new file mode 100644 index 00000000..b06a9707 --- /dev/null +++ b/RegistryServer/QueryImp.cpp @@ -0,0 +1,208 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "QueryImp.h" +#include "util/tc_clientsocket.h" + +extern TC_Config * g_pconf; + +void QueryImp::initialize() +{ + TLOGDEBUG("begin QueryImp init"< QueryImp::findObjectById(const string & id, tars::TarsCurrentPtr current) +{ + vector eps = _db.findObjectById(id); + + ostringstream os; + doDaylog(FUNID_findObjectById,id,eps,vector(),current,os); + + return eps; +} + +tars::Int32 QueryImp::findObjectById4Any(const std::string & id,vector &activeEp,vector &inactiveEp,tars::TarsCurrentPtr current) +{ + int iRet = _db.findObjectById4All(id, activeEp, inactiveEp); + + ostringstream os; + doDaylog(FUNID_findObjectById4Any,id,activeEp,inactiveEp,current,os); + + return iRet; +} + +int QueryImp::findObjectById4All(const std::string & id, vector &activeEp,vector &inactiveEp,tars::TarsCurrentPtr current) +{ + ostringstream os; + + int iRet = _db.findObjectByIdInGroupPriority(id,current->getIp(),activeEp, inactiveEp,os); + + doDaylog(FUNID_findObjectById4All,id,activeEp,inactiveEp,current,os); + + return iRet; +} + +int QueryImp::findObjectByIdInSameGroup(const std::string & id, vector &activeEp,vector &inactiveEp, tars::TarsCurrentPtr current) +{ + ostringstream os; + TLOGINFO(__FUNCTION__ << ":" << __LINE__ << "|" << id << "|" << current->getIp() << endl); + + int iRet = _db.findObjectByIdInGroupPriority(id, current->getIp(), activeEp, inactiveEp, os); + + doDaylog(FUNID_findObjectByIdInSameGroup,id,activeEp,inactiveEp,current,os); + + return iRet; +} + +Int32 QueryImp::findObjectByIdInSameStation(const std::string & id, const std::string & sStation, vector &activeEp, vector &inactiveEp, tars::TarsCurrentPtr current) +{ + ostringstream os; + + int iRet = _db.findObjectByIdInSameStation(id, sStation, activeEp, inactiveEp, os); + + doDaylog(FUNID_findObjectByIdInSameStation,id,activeEp,inactiveEp,current,os); + + return iRet; +} + +Int32 QueryImp::findObjectByIdInSameSet(const std::string & id,const std::string & setId,vector &activeEp,vector &inactiveEp, tars::TarsCurrentPtr current) +{ + vector vtSetInfo = TC_Common::sepstr(setId,"."); + + if (vtSetInfo.size()!=3 ||(vtSetInfo.size()==3&&(vtSetInfo[0]=="*"||vtSetInfo[1]=="*"))) + { + TLOGERROR("QueryImp::findObjectByIdInSameSet:|set full name error[" << id << "_" << setId <<"]|" << current->getIp() << endl); + return -1; + } + + ostringstream os; + int iRet = _db.findObjectByIdInSameSet(id, vtSetInfo, activeEp, inactiveEp, os); + if (-1 == iRet) + { + //未启动set,启动ip分组策略 + return findObjectByIdInSameGroup(id, activeEp, inactiveEp, current); + } + else if (-2 == iRet) + { + //启动了set,但未找到任何服务节点 + TLOGERROR("QueryImp::findObjectByIdInSameSet |no one server found for [" << id << "_" << setId <<"]|" << current->getIp() << endl); + return -1; + } + else if (-3 == iRet) + { + //启动了set,但未找到任何地区set,严格上不应该出现此类情形,配置错误或主调设置错误会引起此类错误 + TLOGERROR("QueryImp::findObjectByIdInSameSet |no set area found [" << id << "_" << setId <<"]|" << current->getIp() << endl); + return -1; + } + + doDaylog(FUNID_findObjectByIdInSameSet,id,activeEp,inactiveEp,current,os,setId); + + return iRet; +} + +void QueryImp::doDaylog(const FUNID eFnId,const string& id,const vector &activeEp, const vector &inactiveEp, const tars::TarsCurrentPtr& current,const ostringstream& os,const string& sSetid) +{ + string sEpList; + for(size_t i = 0; i < activeEp.size(); i++) + { + if(0 != i) + { + sEpList += ";"; + } + sEpList += activeEp[i].host + ":" + TC_Common::tostr(activeEp[i].port); + } + + sEpList += "|"; + + for(size_t i = 0; i < inactiveEp.size(); i++) + { + if(0 != i) + { + sEpList += ";"; + } + sEpList += inactiveEp[i].host + ":" + TC_Common::tostr(inactiveEp[i].port); + } + + switch(eFnId) + { + case FUNID_findObjectById4All: + case FUNID_findObjectByIdInSameGroup: + { + FDLOG("query_idc") << eFunTostr(eFnId)<<"|"<getIp() << "|"<< current->getPort() << "|" << id << "|" <getIp() << "|"<< current->getPort() << "|" << id << "|" <getIp() << "|"<< current->getPort() << "|" << id << "|" < findObjectById(const string & id, tars::TarsCurrentPtr current); + + /** + * 根据id获取所有对象,包括活动和非活动对象 + */ + virtual tars::Int32 findObjectById4Any(const std::string & id, vector &activeEp, vector &inactiveEp, tars::TarsCurrentPtr current); + + /** + * 根据id获取对象所有endpoint列表 + */ + Int32 findObjectById4All(const std::string & id, vector &activeEp, vector &inactiveEp, tars::TarsCurrentPtr current); + + /** + * 根据id获取对象同组endpoint列表 + */ + Int32 findObjectByIdInSameGroup(const std::string & id, vector &activeEp, vector &inactiveEp, tars::TarsCurrentPtr current); + + /** + * 根据id获取对象指定归属地的endpoint列表 + */ + Int32 findObjectByIdInSameStation(const std::string & id, const std::string & sStation, vector &activeEp, vector &inactiveEp, tars::TarsCurrentPtr current); + + /** + * 根据id获取对象同set endpoint列表 + */ + Int32 findObjectByIdInSameSet(const std::string & id,const std::string & setId,vector &activeEp,vector &inactiveEp, tars::TarsCurrentPtr current); + +private: + /** + * 打印按天日志 + */ + void doDaylog(const FUNID eFnId,const string& id,const vector &activeEp, const vector &inactiveEp, const tars::TarsCurrentPtr& current,const std::ostringstream& os,const string& sSetid=""); + + /** + * 转化成字符串 + */ + string eFunTostr(const FUNID eFnId); + +protected: + + //数据库操作 + CDbHandle _db; + +}; + +#endif diff --git a/RegistryServer/ReapThread.cpp b/RegistryServer/ReapThread.cpp new file mode 100644 index 00000000..033956a4 --- /dev/null +++ b/RegistryServer/ReapThread.cpp @@ -0,0 +1,153 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "ReapThread.h" + +extern TC_Config * g_pconf; + +ReapThread::ReapThread() +: _terminate(false) +, _loadObjectsInterval1(10) +, _leastChangedTime1(60) +, _loadObjectsInterval2(3600) +, _leastChangedTime2(30*60) +, _registryTimeout(150) +, _recoverProtect(true) +, _recoverProtectRate(30) +, _heartBeatOff(false) +{ +} + +ReapThread::~ReapThread() +{ + if (isAlive()) + { + terminate(); + notifyAll(); + getThreadControl().join(); + } +} + +int ReapThread::init() +{ + TLOGDEBUG("begin ReapThread init"<((*g_pconf).get("/tars/reap", "10")); + //第一阶段加载最近时间更新的记录,默认是60秒 + _leastChangedTime1 = TC_Common::strto((*g_pconf).get("/tars/reap", "150")); + + _loadObjectsInterval2 = TC_Common::strto((*g_pconf).get("/tars/reap", "300")); + + //主控心跳超时时间 + _registryTimeout = TC_Common::strto((*g_pconf)["/tars/reap"]); + + //是否启用DB恢复保护功能 + _recoverProtect = (*g_pconf).get("/tars/reap", "Y") == "N"?false:true; + + //启用DB恢复保护功能状态下极限值 + _recoverProtectRate = TC_Common::strto((*g_pconf).get("/tars/reap", "30")); + + //是否关闭更新主控心跳时间,一般需要迁移主控服务是,设置此项为Y + _heartBeatOff = (*g_pconf).get("/tars/reap", "N") == "Y"?true:false; + + //最小值保护 + _loadObjectsInterval1 = _loadObjectsInterval1 < 5 ? 5 : _loadObjectsInterval1; + + _registryTimeout = _registryTimeout < 5 ? 5 : _registryTimeout; + + _recoverProtectRate = _recoverProtectRate < 1 ? 30: _recoverProtectRate; + + _recoverProtect = false; + + //加载对象列表 + _db.loadObjectIdCache(_recoverProtect, _recoverProtectRate,0,true, true); + + TLOGDEBUG("ReapThread init ok."<getNow(); + + //全量加载时间 + time_t tLastLoadObjectsStep2 = TC_TimeProvider::getInstance()->getNow(); + + time_t tLastQueryServer = 0; + time_t tNow; + while(!_terminate) + { + try + { + tNow = TC_TimeProvider::getInstance()->getNow(); + + //加载对象列表 + if(tNow - tLastLoadObjectsStep1 >= _loadObjectsInterval1) + { + tLastLoadObjectsStep1 = tNow; + + _db.updateRegistryInfo2Db(_heartBeatOff); + + if(tNow - tLastLoadObjectsStep2 >= _loadObjectsInterval2) + { + tLastLoadObjectsStep2 = tNow; + //全量加载,_leastChangedTime2参数没有意义 + _db.loadObjectIdCache(_recoverProtect, _recoverProtectRate,_leastChangedTime2,true, false); + } + else + { + _db.loadObjectIdCache(_recoverProtect, _recoverProtectRate,_leastChangedTime1,false, false); + } + + } + + //轮询心跳超时的主控 + if(tNow - tLastQueryServer >= _registryTimeout) + { + tLastQueryServer = tNow; + _db.checkRegistryTimeout(_registryTimeout); + } + + + TC_ThreadLock::Lock lock(*this); + timedWait(100); //ms + } + catch(exception & ex) + { + TLOGERROR("ReapThread exception:" << ex.what() << endl); + } + catch(...) + { + TLOGERROR("ReapThread unknown exception:" << endl); + } + } +} + + + diff --git a/RegistryServer/ReapThread.h b/RegistryServer/ReapThread.h new file mode 100644 index 00000000..f778f649 --- /dev/null +++ b/RegistryServer/ReapThread.h @@ -0,0 +1,103 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __REAP_THREAD_H__ +#define __REAP_THREAD_H__ + +#include +#include "util/tc_thread.h" +#include "DbHandle.h" + +using namespace tars; + +////////////////////////////////////////////////////// +/** + * 用于执行定时操作的线程类 + */ +class ReapThread : public TC_Thread, public TC_ThreadLock +{ +public: + /** + * 构造函数 + */ + ReapThread(); + + /** + * 析构函数 + */ + ~ReapThread(); + + /** + * 结束线程 + */ + void terminate(); + + /** + * 初始化 + */ + int init(); + + /** + * 轮询函数 + */ + virtual void run(); + +protected: + /* + * 线程结束标志 + */ + bool _terminate; + + /* + * 数据库操作 + */ + CDbHandle _db; + + /* + * 加载对象列表的时间间隔,单位是秒 + * 第一阶段加载时间 consider + */ + int _loadObjectsInterval1; + int _leastChangedTime1; + + /* + * 全量加载时间,单位是秒 + */ + int _loadObjectsInterval2; + int _leastChangedTime2; + + /* + * registry心跳超时时间 + */ + int _registryTimeout; + + /* + * 是否启用DB恢复保护功能,默认为打开 + */ + bool _recoverProtect; + + /* + * 启用DB恢复保护功能状态下极限值 + */ + int _recoverProtectRate; + + /* + * 主控心跳时间更新开关 + */ + bool _heartBeatOff; +}; + +#endif diff --git a/RegistryServer/RegistryImp.cpp b/RegistryServer/RegistryImp.cpp new file mode 100644 index 00000000..e19bad94 --- /dev/null +++ b/RegistryServer/RegistryImp.cpp @@ -0,0 +1,122 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include + +#include "RegistryImp.h" +#include "RegistryProcThread.h" +#include "RegistryServer.h" + +//初始化配置db连接 +extern TC_Config * g_pconf; +extern RegistryServer g_app; + +void RegistryImp::initialize() +{ + TLOGDEBUG("begin RegistryImp init"<put(procInfo); + + return 0; +} + +vector RegistryImp::getServers(const std::string & app,const std::string & serverName,const std::string & nodeName,tars::TarsCurrentPtr current) +{ + return _db.getServers(app, serverName, nodeName); +} + +int RegistryImp::updateServer(const string & nodeName, const string & app, const string & serverName, const tars::ServerStateInfo & stateInfo, tars::TarsCurrentPtr current) +{ + return _db.updateServerState(app, serverName, nodeName, "present_state", stateInfo.serverState, stateInfo.processId); +} + +int RegistryImp::updateServerBatch(const std::vector & vecStateInfo, tars::TarsCurrentPtr current) +{ + return _db.updateServerStateBatch(vecStateInfo); +} + +int RegistryImp::destroy(const string & name, tars::TarsCurrentPtr current) +{ + return _db.destroyNode(name); +} + +int RegistryImp::reportVersion(const string & app, const string & serverName, const string & nodeName, const string & version, tars::TarsCurrentPtr current) +{ + RegistryProcInfo procInfo; + procInfo.appName = app; + procInfo.serverName = serverName; + procInfo.nodeName = nodeName; + procInfo.tarsVersion = version; + procInfo.cmd = EM_REPORTVERSION; + + //放入异步处理线程中 + g_app.getRegProcThread()->put(procInfo); + + return 0; +} + +int RegistryImp::getNodeTemplate(const std::string & nodeName,std::string &profileTemplate,tars::TarsCurrentPtr current) +{ + string sTemplateName; + int iRet = _db.getNodeTemplateName(nodeName, sTemplateName); + if(iRet != 0 || sTemplateName == "") + { + //默认模板配置 + sTemplateName = (*g_pconf)["/tars/nodeinfo"]; + } + + string sDesc; + profileTemplate = _db.getProfileTemplate(sTemplateName, sDesc); + + TLOGDEBUG(nodeName << " get sTemplateName:" << sTemplateName << " result:" << sDesc << endl); + + return 0; +} + +int RegistryImp::getClientIp(std::string &sClientIp,tars::TarsCurrentPtr current) +{ + sClientIp = current->getIp(); + TLOGDEBUG("RegistryImp::getClientIp ip: " << sClientIp << endl); + + return 0; +} + +int RegistryImp::updatePatchResult(const PatchResult & result, tars::TarsCurrentPtr current) +{ + TLOGDEBUG( "RegistryImp::updatePatchResult " << result.sApplication + "." + result.sServerName + "_" + result.sNodeName << "|V:" << result.sVersion << "|U:" << result.sUserName << endl); + + return _db.setPatchInfo(result.sApplication, result.sServerName, result.sNodeName, result.sVersion, result.sUserName); +} + diff --git a/RegistryServer/RegistryImp.h b/RegistryServer/RegistryImp.h new file mode 100644 index 00000000..c73872a5 --- /dev/null +++ b/RegistryServer/RegistryImp.h @@ -0,0 +1,163 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __REGISTRY_IMP_H__ +#define __REGISTRY_IMP_H__ + +#include "util/tc_common.h" +#include "util/tc_config.h" + +#include "Registry.h" +#include "DbHandle.h" + +using namespace tars; + +////////////////////////////////////////////////////// +/* + * 提供给node调用的接口类 + */ +class RegistryImp: public Registry +{ +public: + /** + * 构造函数 + */ + RegistryImp(){}; + + /** + * 初始化 + */ + virtual void initialize(); + + /** + ** 退出 + */ + virtual void destroy() {}; + + /** + * 获取数据 + * @param k + * @param v + * + * @return int + */ + int get(int &i, tars::TarsCurrentPtr current); + + /** + * node启动的时候往registry注册一个session + * + * @param name node名称 + * @param ni node详细信息 + * @param li node机器负载信息 + * + * @return 注册是否成功 + */ + virtual int registerNode(const string & name, const NodeInfo & ni, const LoadInfo & li, tars::TarsCurrentPtr current); + + /** + * node上报心跳负载 + * + * @param name node名称 + * @param li node机器负载信息 + * + * @return 心跳接收状态 + */ + virtual int keepAlive(const string& name, const LoadInfo & li, tars::TarsCurrentPtr current); + + /** + * 获取在该node部署的server列表 + * + * @param name node名称 + * + * @return server名称列表 + */ + virtual vector getServers(const std::string & app, const std::string & serverName, const std::string & nodeName, tars::TarsCurrentPtr current); + + /** + * 更新server状态 + * + * @param nodeName : node id + * @param app: 应用 + * @param serverName: server 名 + * @param state : server状态 + * + * @return server信息列表 + */ + virtual int updateServer(const string & nodeName, const string & app, const string & serverName, const tars::ServerStateInfo & stateInfo, tars::TarsCurrentPtr current); + + /** + * 量批更新server状态 + * + * @param vecStateInfo : 批量server状态 + * + * @return server信息列表 + */ + virtual int updateServerBatch(const std::vector & vecStateInfo, tars::TarsCurrentPtr current); + + /** + * node停止,释放node的会话 + * + * @param name node名称 + */ + virtual int destroy(const string & name, tars::TarsCurrentPtr current); + + /** + * 上报server的tars库版本 + * @param app: 应用 + * @param serverName: server 名 + * @param nodeName : node id + * @param version: server基于的tars版本号 + * + * @return 0-成功 others-失败 + */ + virtual int reportVersion(const string & app, const string & serverName, const string & nodeName, const string & version, tars::TarsCurrentPtr current); + + /** + * 获取node的模板配置 + * @param nodeName: node名称 + * @param out profileTemplate: 对应模板内容 + * + * @return 0-成功 others-失败 + */ + virtual tars::Int32 getNodeTemplate(const std::string & nodeName, std::string &profileTemplate, tars::TarsCurrentPtr current); + + /** + * node通过接口获取连接上主控的node ip + * @param sNodeIp: node 的ip + * + * @return 0-成功 others-失败 + */ + virtual tars::Int32 getClientIp(std::string &sClientIp, tars::TarsCurrentPtr current); + + /** + * 发布任务完成后,UPDATE版本号和发布人 + * @param PatchResult: 发布结果 + * + * @return 0-成功 othres-失败 + */ + virtual tars::Int32 updatePatchResult(const PatchResult & result, tars::TarsCurrentPtr current); + +protected: + + /* + * 数据库操作 + */ + CDbHandle _db; + +}; + + +#endif diff --git a/RegistryServer/RegistryProcThread.cpp b/RegistryServer/RegistryProcThread.cpp new file mode 100644 index 00000000..ee68da4f --- /dev/null +++ b/RegistryServer/RegistryProcThread.cpp @@ -0,0 +1,139 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "RegistryProcThread.h" + +using namespace tars; + +//初始化数据库实例用 +extern TC_Config * g_pconf; + +////////////////////////////////////////////////////// +RegistryProcThread::RegistryProcThread() +: _terminate(false) +{ + TLOGDEBUG("RegistryProcThread init ok"<isAlive()) + { + _runners[i]->terminate(); + + _queue.notifyT(); + } + } + + for (uint32_t i = 0; i < _runners.size(); ++i) + { + if(_runners[i]->isAlive()) + { + _runners[i]->getThreadControl().join(); + } + } + + _queue.clear(); + +} + +void RegistryProcThread::start(int num) +{ + for (int i = 0; i < num; ++i) + { + RegistryProcThreadRunnerPtr r = new RegistryProcThreadRunner(this); + + r->start(); + + _runners.push_back(r); + } +} + +void RegistryProcThread::put(const RegistryProcInfo& info) +{ + if(!_terminate) + { + _queue.push_back(info); + } +} + +bool RegistryProcThread::pop(RegistryProcInfo& info) +{ + return _queue.pop_front(info,1000); +} + +////////////////////////////////////////////////////// +RegistryProcThreadRunner::RegistryProcThreadRunner(RegistryProcThread* proc) +: _terminate(false) +, _proc(proc) +{ + _db.init(g_pconf); +} + +void RegistryProcThreadRunner::terminate() +{ + _terminate = true; +} + +void RegistryProcThreadRunner::run() +{ + while (!_terminate) + { + try + { + RegistryProcInfo info; + if(_proc->pop(info) && !_terminate) + { + TLOGDEBUG("RegistryProcThreadRunner:run cmd:"< RegistryProcThreadRunnerPtr; + +////////////////////////////////////////////////////// +/** + * 处理异步操作的线程池对象 + */ +class RegistryProcThread : public TC_HandleBase +{ +public: + /** + * 构造函数 + */ + RegistryProcThread(); + + /** + * 析构函数 + */ + virtual ~RegistryProcThread(); + + /** + * 停止运行 + */ + void terminate(); + + /** + * 插入请求 + */ + void put(const RegistryProcInfo& info); + + /** + * 取请求 + */ + bool pop(RegistryProcInfo& info); + + /** + * 启动处理请求线程 + */ + void start(int num=1); + + friend class RegistryProcThreadRunner; + +protected: + /* + * 线程结束标志 + */ + bool _terminate; + + /* + * 请求队列 + */ + TC_ThreadQueue _queue; + + /* + * 线程对象集合 + */ + vector _runners; +}; + +typedef TC_AutoPtr RegistryProcThreadPtr; + +////////////////////////////////////////////////////// +/** + * 处理异步操作的线程 + */ +class RegistryProcThreadRunner : public TC_Thread, public TC_HandleBase +{ +public: + /* + * 构造函数 + */ + RegistryProcThreadRunner(RegistryProcThread* proc); + + /* + * 线程执行函数 + */ + virtual void run(); + + /* + * 停止运行 + */ + void terminate(); + +private: + /* + * 线程结束标志 + */ + bool _terminate; + + /* + * 线程池对象指针 + */ + RegistryProcThread * _proc; + + /* + * 访问主控db的处理类 + */ + CDbHandle _db; +}; + +#endif diff --git a/RegistryServer/RegistryServer.cpp b/RegistryServer/RegistryServer.cpp new file mode 100644 index 00000000..15cf7fe0 --- /dev/null +++ b/RegistryServer/RegistryServer.cpp @@ -0,0 +1,127 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "RegistryServer.h" + +extern TC_Config *g_pconf; + +void RegistryServer::initialize() +{ + TLOGDEBUG("RegistryServer::initialize..." << endl); + + try + { + //加载registry对象的端口信息 + loadServantEndpoint(); + + //ReapThread初始化时会用到 + TarsTimeLogger::getInstance()->initFormat("group_id", "%Y%m%d%H"); + TarsTimeLogger::getInstance()->enableRemote("group_id", true); + + //全量和增量加载路由信息的线程 + _reapThread.init(); + _reapThread.start(); + + //检查node超时的线程 + _checkNodeThread.init(); + _checkNodeThread.start(); + + //监控所有服务状态的线程 + _checksetingThread.init(); + _checksetingThread.start(); + + //异步处理线程 + _registryProcThread = new RegistryProcThread(); + int num = TC_Common::strto(g_pconf->get("/tars/reap", "3")); + _registryProcThread->start(num); + + //供node访问的对象 + addServant((*g_pconf)["/tars/objname"]); + + //供tars的服务获取路由的对象 + addServant((*g_pconf)["/tars/objname"]); + + TarsTimeLogger::getInstance()->enableRemote("", false); + + TarsTimeLogger::getInstance()->initFormat("query_set", "%Y%m%d%H"); + TarsTimeLogger::getInstance()->enableRemote("query_set", false); + + TarsTimeLogger::getInstance()->initFormat("query_idc", "%Y%m%d%H"); + TarsTimeLogger::getInstance()->enableRemote("query_idc", false); + + TarsTimeLogger::getInstance()->initFormat("query", "%Y%m%d%H"); + TarsTimeLogger::getInstance()->enableRemote("query", false); + } + catch (TC_Exception& ex) + { + TLOGERROR("RegistryServer initialize exception:" << ex.what() << endl); + cerr << "RegistryServer initialize exception:" << ex.what() << endl; + exit(-1); + } + + TLOGDEBUG("RegistryServer::initialize OK!" << endl); +} + + +void RegistryServer::destroyApp() +{ + if (_registryProcThread) + { + _registryProcThread->terminate(); + } + + TLOGDEBUG("RegistryServer::destroyApp ok" << endl); +} + +RegistryProcThread* RegistryServer::getRegProcThread() +{ + return _registryProcThread.get(); +} + +int RegistryServer::loadServantEndpoint() +{ + map mapAdapterServant = ServantHelperManager::getInstance()->getAdapterServant(); + + map::iterator iter; + for (iter = mapAdapterServant.begin(); iter != mapAdapterServant.end(); iter++) + { + TC_Endpoint ep = getEpollServer()->getBindAdapter(iter->first)->getEndpoint(); + + _mapServantEndpoint[iter->second] = ep.toString(); + + TLOGDEBUG("registry obj: " << iter->second << " = " << ep.toString() << endl); + } + + return 0; +} + +TC_Endpoint RegistryServer::getAdapterEndpoint(const string& name) const +{ + TC_Endpoint locator; + + try + { + locator = getEpollServer()->getBindAdapter(name)->getEndpoint(); + } + catch (exception& ex) + { + TLOGERROR("RegistryServer::getAdapterEndpoint exception: " << ex.what() << endl); + } + + return locator; +} + + diff --git a/RegistryServer/RegistryServer.h b/RegistryServer/RegistryServer.h new file mode 100644 index 00000000..50f3b844 --- /dev/null +++ b/RegistryServer/RegistryServer.h @@ -0,0 +1,84 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "servant/Application.h" +#include "RegistryImp.h" +#include "QueryImp.h" +#include "ReapThread.h" +#include "CheckNodeThread.h" +#include "CheckSettingState.h" +#include "RegistryProcThread.h" + +using namespace tars; + +////////////////////////////////////////////////////// +/** + * 主控服务 + */ +class RegistryServer : public Application +{ +public: + /** + * 初始化, 服务启动时会调用一次 + */ + virtual void initialize(); + + /** + * 析构, 服务退出时会调用一次 + */ + virtual void destroyApp(); + + /** + * 获取registry对象的端口信息 + */ + map getServantEndpoint() { return _mapServantEndpoint; } + + /** + * 加载registry对象的端口信息 + */ + int loadServantEndpoint(); + + /** + * 获取异步处理线程的对象指针 + */ + RegistryProcThread * getRegProcThread(); + + /** + * 根据name获取对应的ip、端口等信息 + */ + TC_Endpoint getAdapterEndpoint(const string& name ) const; + +protected: + + /* + * 用于执行定时操作的线程对象 + */ + ReapThread _reapThread; //全量和增量加载路由信息的线程 + + CheckNodeThread _checkNodeThread; //监控tarsnode超时的线程 + + CheckSettingState _checksetingThread; //监控所有服务状态的线程 + + RegistryProcThreadPtr _registryProcThread; //处理心跳、上报等的异步线程 + + /* + * 对象-适配器 列表 + */ + map _mapServantEndpoint; + +}; + + diff --git a/RegistryServer/main.cpp b/RegistryServer/main.cpp new file mode 100644 index 00000000..b5262021 --- /dev/null +++ b/RegistryServer/main.cpp @@ -0,0 +1,42 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "RegistryServer.h" +#include + +using namespace tars; + +RegistryServer g_app; +TC_Config * g_pconf; + +int main(int argc, char *argv[]) +{ + try + { + g_pconf = & g_app.getConfig(); + g_app.main(argc, argv); + + g_app.waitForShutdown(); + } + catch(exception &ex) + { + cerr<< ex.what() << endl; + } + + return 0; +} + + diff --git a/StatServer/CMakeLists.txt b/StatServer/CMakeLists.txt new file mode 100644 index 00000000..59fd9659 --- /dev/null +++ b/StatServer/CMakeLists.txt @@ -0,0 +1,6 @@ + +set(MODULE "tarsstat") + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/deploy/${MODULE}/) + +complice_module(${MODULE}) diff --git a/StatServer/ReapSSDThread.cpp b/StatServer/ReapSSDThread.cpp new file mode 100644 index 00000000..4e5f5e81 --- /dev/null +++ b/StatServer/ReapSSDThread.cpp @@ -0,0 +1,451 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "ReapSSDThread.h" +#include "util/tc_config.h" +#include "StatServer.h" + + +ReapSSDProcThread::ReapSSDProcThread(ReapSSDThread * proc) +: _terminate(false) +, _proc(proc) +{ +} + +ReapSSDProcThread::~ReapSSDProcThread() +{ + if(isAlive()) + { + terminate(); + getThreadControl().join(); + } + _queue.clear(); +} + +void ReapSSDProcThread::terminate() +{ + _terminate = true; + + _queue.notifyT(); +} + +void ReapSSDProcThread::put(QueueItem data) +{ + if(!_terminate) + { + _queue.push_back(data); + } +} + +bool ReapSSDProcThread::pop(QueueItem & data) +{ + return _queue.pop_front(data, 1000); +} + +int ReapSSDProcThread::sendAlarmSMS(const string &sMsg) +{ + string errInfo = " ERROR:" + ServerConfig::LocalIp + "_" + sMsg; + TARS_NOTIFY_ERROR(errInfo); + + return 0; +} + +void ReapSSDProcThread::run() +{ + string sDate1(""); + string sFlag1(""); + string sDate2(""); + string sFlag2(""); + + while (!_terminate) + { + try + { + sDate1 = ""; + sFlag1 = ""; + sDate2 = ""; + sFlag2 = ""; + + QueueItem item; + + if(pop(item)) + { + if(item._statmsg != NULL) + { + int64_t iBegin = TNOWMS; + int64_t iEnd = 0; + + StatDbManager::getInstance()->insert2MultiDbs(item._index, *item._statmsg, item._date, item._tflag); + + iEnd = TNOWMS; + + TLOGDEBUG("ReapSSDProcThread::run stat ip:" << ServerConfig::LocalIp << "|dbIndex:" << item._index << "|" << StatDbManager::getInstance()->getIpAndPort(item._index) + << "|date:" << item._date << "|tflag:" << item._tflag << "|timecost(ms):" << (iEnd - iBegin) << "|iBegin:" << iBegin << "|iEnd:" << iEnd << endl); + + FDLOG("CountStat") << "ReapSSDProcThread::run stat ip:" << ServerConfig::LocalIp << "|dbIndex:" << item._index << "|" << StatDbManager::getInstance()->getIpAndPort(item._index) + << "|date:" << item._date << "|tflag:" << item._tflag << "|timecost(ms):" << (iEnd - iBegin) << "|iBegin:" << iBegin << "|iEnd:" << iEnd << endl; + + if((iEnd - iBegin)/1000 > (g_app.getInserInterv() - 2) * 60) + { + FDLOG("CountStat") << "stat ip:" << ServerConfig::LocalIp << "|ReapSSDProcThread::run timeout 8 minute." << endl; + string sMsg("stat ip:"); + sMsg += ServerConfig::LocalIp; + sMsg += " ReapSSDProcThread::run write db:"; + sMsg += StatDbManager::getInstance()->getIpAndPort(item._index); + sMsg += "|timeout "; + sMsg += TC_Common::tostr(g_app.getInserInterv() - 2); + sMsg += " Minute."; + + sendAlarmSMS(sMsg); + } + + delete item._statmsg; + item._statmsg = NULL; + } + else + { + TLOGERROR("ReapSSDProcThread::run item._statmsg == NULL." << endl); + } + } + } + catch(exception& e) + { + TLOGERROR("ReapSSDProcThread::run exception:" << e.what() << endl); + FDLOG("CountStat") << "ReapSSDProcThread::run exception:" << e.what() << endl; + } + } +} +////////////////////////////////////////////////////////////// +ReapSSDThread::ReapSSDThread() +: _terminate(false) +, _curWeight(0) +, _lastSq(-1) +{ + TLOGDEBUG("ReapSSDThread begin ok" << endl); +} + +ReapSSDThread::~ReapSSDThread() +{ + if (isAlive()) + { + terminate(); + + getThreadControl().join(); + } +} + +void ReapSSDThread::terminate() +{ + TLOGDEBUG("ReapSSDThread terminate." << endl); + + _terminate = true; + + TC_ThreadLock::Lock lock(*this); + + notifyAll(); +} + +void ReapSSDThread::run() +{ + int iInsertDataNum = StatDbManager::getInstance()->getDbIpNum(); + + for(int i = 0; i < iInsertDataNum; ++i) + { + ReapSSDProcThread *r = new ReapSSDProcThread(this); + + r->start(); + + _runners.push_back(r); + } + + string sDate,sTime; + + int dbNumber = StatDbManager::getInstance()->getDbNumber(); + + string sRandOrder; + + uint64_t iTotalNum = 0; + + int iLastIndex = -1; + + FDLOG("CountStat") << "stat ip:" << ServerConfig::LocalIp << "|ReapSSDThread::run iInsertDataThread:" << iInsertDataNum << "|dbNumber:" << dbNumber << endl; + + while (!_terminate) + { + try + { + //双buffer中一个buffer入库 + int iBufferIndex = !(g_app.getSelectBufferIndex()); + int64_t iInterval = 3; + if(iBufferIndex != iLastIndex && g_app.getSelectBuffer(iBufferIndex, iInterval)) + { + iLastIndex = iBufferIndex; + + iTotalNum = 0; + + vector vAllStatMsg; + for(int iStatIndex = 0; iStatIndex < dbNumber; ++iStatIndex) + { + vAllStatMsg.push_back(new StatMsg()); + } + + int64_t tBegin = TNOWMS; + + getDataFromBuffer(iBufferIndex, vAllStatMsg, iTotalNum); + + int64_t tEnd = TNOWMS; + + TLOGDEBUG("stat ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iBufferIndex << "|ReapSSDThread::run getDataFromBuffer timecost(ms):" << (tEnd - tBegin) << endl); + FDLOG("CountStat") << "stat ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iBufferIndex << "|ReapSSDThread::run getDataFromBuffer timecost(ms):" << (tEnd - tBegin) << endl; + + TLOGDEBUG("stat ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iBufferIndex << "|ReapSSDThread::run insert begin _vAllStatMsg.size:" << vAllStatMsg.size() << "|record num:" << iTotalNum << endl); + FDLOG("CountStat") << "stat ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iBufferIndex << "|ReapSSDThread::run insert begin _vAllStatMsg.size:" << vAllStatMsg.size() << "|record num:" << iTotalNum << endl; + + if(iTotalNum <= 0) + { + for(int iStatIndex = 0; iStatIndex < dbNumber; ++iStatIndex) + { + delete vAllStatMsg[iStatIndex]; + } + + vAllStatMsg.clear(); + } + else + { + + string sFile=""; + string sDate=""; + string sFlag=""; + time_t time=0; + g_app.getTimeInfo(time,sDate,sFlag); + + //size_t iSize = vAllStatMsg.size(); + + QueueItem item; + int iInsertThreadIndex = 0; + sRandOrder = g_app.getRandOrder(); + + if (sRandOrder == "") + { + sRandOrder = "0"; + } + + map >& mIpHasDbInfo = StatDbManager::getInstance()->getIpHasDbInfo(); + map >::iterator m_iter = mIpHasDbInfo.begin(); + + while(m_iter != mIpHasDbInfo.end()) + { + vector &vDb = m_iter->second; + + for(size_t i = 0; i < vDb.size(); ++i) + { + int k = (i + TC_Common::strto(sRandOrder)) % vDb.size(); + + item._index = vDb[k]; + item._date = sDate; + item._tflag = sFlag; + item._statmsg = vAllStatMsg[item._index]; + + iInsertThreadIndex = StatDbManager::getInstance()->getDbToIpIndex(vDb[k]); + + assert(iInsertThreadIndex >= 0); + + _runners[iInsertThreadIndex]->put(item); + } + + ++m_iter; + } + + if(_terminate) + { + break; + } + } + + for(int k = 0; k < g_app.getBuffNum(); ++k) + { + StatHashMap *pHashMap = g_app.getHashMapBuff(iBufferIndex, k); + pHashMap->clear(); + } + + TLOGDEBUG("stat ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iBufferIndex << "|ReapSSDThread::run insert record num:" << iTotalNum << "|tast patch finished." << endl); + FDLOG("CountStat") << "stat ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iBufferIndex << "|ReapSSDThread::run insert record num:" << iTotalNum << "|tast patch finished." << endl; + } + + } + catch(exception& ex) + { + TLOGERROR("ReapSSDThread::run exception:"<< ex.what() << endl); + } + catch(...) + { + TLOGERROR("ReapSSDThread::run ReapSSDThread unkonw exception catched" << endl); + } + + TC_ThreadLock::Lock lock(*this); + timedWait(REAP_INTERVAL); + } + + TLOGDEBUG("ReapSSDThread run setITerminateFlag true." << endl); + + StatDbManager::getInstance()->setITerminateFlag(true); + + for(size_t i = 0; i < _runners.size(); ++i) + { + if(_runners[i]->isAlive()) + { + _runners[i]->terminate(); + + _runners[i]->getThreadControl().join(); + } + } + + for(size_t i = 0; i < _runners.size(); ++i) + { + if(_runners[i]) + { + delete _runners[i]; + _runners[i] = NULL; + } + } + + TLOGDEBUG("ReapSSDThread run terminate." << endl); +} + +int ReapSSDThread::getIndexWithWeighted(int iMaxDb,int iGcd,int iMaxW,const vector& vDbWeight) +{ + while (true){ + + _lastSq = (_lastSq + 1) % iMaxDb; + + if (_lastSq == 0) + { + _curWeight = _curWeight - iGcd; + if (_curWeight <= 0) + { + _curWeight = iMaxW; + if(_curWeight == 0) + { + return 0; + } + } + } + + if (vDbWeight[_lastSq] >= _curWeight) + { + return _lastSq; + } + } +} +void ReapSSDThread::getDataFromBuffer(int iIndex, vector &vAllStatMsg, uint64_t &iTotalNum) +{ + TLOGDEBUG("ReapSSDThread::getDataFromBuffer iIndex:" << iIndex << "|begin..." << endl); + + try + { + int iCount = 0,dbSeq=0; + + //获取db个数 + int dbNumber = StatDbManager::getInstance()->getDbNumber(); + + vector vDbWeight; + int iGcd = 0,iMaxW = 0; + + StatDbManager::getInstance()->getDbWeighted(iGcd,iMaxW,vDbWeight); + + bool bEnable = StatDbManager::getInstance()->IsEnableWeighted(); + + for(int k = 0; k < g_app.getBuffNum(); ++k) + { + if(_terminate) + { + break; + } + + StatHashMap *pHashMap = g_app.getHashMapBuff(iIndex, k); + + if(pHashMap->size() == 0) + { + continue ; + } + + FDLOG("CountStat") << "stat ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iIndex << "|ReapSSDThread::getData load hashmap k:" << k << endl; + + HashMap::lock_iterator it = pHashMap->beginSetTime(); + while ( it != pHashMap->end() ) + { + if(_terminate) + { + break; + } + + StatMicMsgHead head; + StatMicMsgBody body; + int ret = it->get( head, body ); + if ( ret < 0 ) + { + ++it; + continue; + } + + if (dbNumber > 0) + { + if(bEnable)//按权重入库 + { + dbSeq = getIndexWithWeighted(dbNumber,iGcd,iMaxW,vDbWeight); + TLOGINFO("ReapSSDThread::getIndexWithWeighted |" << dbSeq << endl); + } + else + { + dbSeq = iCount % dbNumber; + } + + (*(vAllStatMsg[dbSeq]))[head] = body; + } + + iCount++; + + ++it; + } + + } + + iTotalNum = iCount; + + TLOGDEBUG("ReapSSDThread::getDataFromBuffer Buffer Index:" << iIndex << "|get total size:" << iCount << endl); + FDLOG("CountStat") << "stat ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iIndex << "|ReapSSDThread::getData get total size:" << iCount << "|end..." << endl; + } + catch (exception& ex) + { + TLOGERROR("ReapSSDThread::getDataFromBuffer exception:" << ex.what() << endl); + FDLOG("CountStat") << "stat ip:" << ServerConfig::LocalIp << "|Buffer Index:" << iIndex << "|ReapSSDThread::getData exception:" << ex.what() << endl; + + string sMsg("ReapSSDThread::getDataFromBuffer Buffer Index:"); + sMsg += TC_Common::tostr(iIndex); + sMsg += " exception:"; + sMsg += ex.what(); + sendAlarmSMS(sMsg); + } +} + +int ReapSSDThread::sendAlarmSMS(const string &sMsg) +{ + string errInfo = " ERROR:" + ServerConfig::LocalIp + "_" + sMsg; + TARS_NOTIFY_ERROR(errInfo); + + return 0; +} + diff --git a/StatServer/ReapSSDThread.h b/StatServer/ReapSSDThread.h new file mode 100644 index 00000000..1424d6f9 --- /dev/null +++ b/StatServer/ReapSSDThread.h @@ -0,0 +1,141 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __REAP_SSD_THREAD_H_ +#define __REAP_SSD_THREAD_H_ + +#include +#include "util/tc_thread.h" +#include "util/tc_mysql.h" +#include "servant/StatF.h" +#include "util/tc_common.h" +#include "servant/TarsLogger.h" +#include "StatImp.h" +#include "StatDbManager.h" + +using namespace tars; + +//////////////////////////////////////// +class QueueItem +{ +public: + size_t _index; + string _date; + string _tflag; + StatMsg *_statmsg; + + QueueItem() + : _index(0) + , _date("") + , _tflag("") + , _statmsg(NULL) + {} +}; +//////////////////////////////////////// +class ReapSSDThread; +//////////////////////////////////////// +/** + * 向数据库插入数据的线程类 + */ +class ReapSSDProcThread : public TC_Thread +{ +public: + enum + { + TIME_INTERVAL = 5000//更新业务线程时间 + }; + ReapSSDProcThread(ReapSSDThread * proc); + + ~ReapSSDProcThread(); + + void terminate(); + + virtual void run(); + + void put(QueueItem data); + + bool pop(QueueItem & data); + + int sendAlarmSMS(const string &sMsg); + +private: + bool _terminate; + + ReapSSDThread * _proc; + + TC_ThreadQueue _queue; +}; +//////////////////////////////////////// +/** + * 用于执行定时操作的线程类 + */ +class ReapSSDThread : public TC_Thread,public TC_ThreadLock +{ +public: + /** + * 定义常量 + */ + enum + { + REAP_INTERVAL = 5000, /**轮训入库间隔时间**/ + }; + /** + * 构造 + */ + ReapSSDThread(); + + /** + * 析够 + */ + ~ReapSSDThread(); + + /** + * 结束线程 + */ + void terminate(); + + /** + * 轮询函数 + */ + virtual void run(); + +private: + /* + * 从buffer中取数据 + */ + void getDataFromBuffer(int iIndex, vector &vAllStatMsg, uint64_t &iTotalNum); + + int sendAlarmSMS(const string &sMsg); + + /** + * 通过权重轮询调度算法获取要插入数据的db index + * @param iMaxDb db个数 + * @param iGcd 所有权重的最大公约数 + * @param iMaxW 最大权重值 + * @param vDbWeight 所有db的权重值 + * + * @return int + */ + int getIndexWithWeighted(int iMaxDb,int iGcd,int iMaxW,const vector& vDbWeight); + +private: + bool _terminate; + int _curWeight; + int _lastSq; + vector _runners; +}; + +#endif diff --git a/StatServer/StatDbManager.cpp b/StatServer/StatDbManager.cpp new file mode 100644 index 00000000..eb080671 --- /dev/null +++ b/StatServer/StatDbManager.cpp @@ -0,0 +1,671 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "StatDbManager.h" +#include "util/tc_config.h" +#include "StatServer.h" +#include "StatHashMap.h" + +/////////////////////////////////////////////////////////// +StatDbManager::StatDbManager() +: _terminate(false) +, _lastDayTimeTable("") +{ + TLOGDEBUG("begin StatDbManager init" << endl); + + _sql = (*g_pconf)["/tars"]; + _sqlStatus = g_pconf->get("/tars", ""); + _tbNamePre = g_pconf->get("/tars/db","t_stat_realtime_"); + _maxInsertCount = TC_Common::strto(g_pconf->get("/tars/reapSql","1000")); + + //默认不使用权重 + _enableWeighted = TC_Common::strto(g_pconf->get("/tars/","0")); + + size_t iInsertDbThreaad = TC_Common::strto(g_pconf->get("/tars/reapSql","4")); + + if (_sqlStatus == "") + { + _sqlStatus = "CREATE TABLE `t_ecstatus` ( " + " `id` int(11) NOT NULL auto_increment, " + " `appname` varchar(64) NOT NULL default '', " + " `action` tinyint(4) NOT NULL default '0', " + " `checkint` smallint(6) NOT NULL default '10', " + " `lasttime` varchar(16) NOT NULL default '', " + " PRIMARY KEY (`appname`,`action`), " + " UNIQUE KEY `id` (`id`) " + " ) ENGINE=HEAP DEFAULT CHARSET=utf8"; + } + + string sCutType = g_pconf->get("/tars/reapSql","hour"); + if (sCutType == "day") + { + _eCutType = CUT_BY_DAY; + } + else if (sCutType == "minute") + { + _eCutType = CUT_BY_MINUTE; + } + else + { + _eCutType = CUT_BY_HOUR; + } + + vector vDb =g_pconf->getDomainVector("/tars/multidb"); + + _dbNumber = vDb.size(); + + TLOGDEBUG("StatDbManager init multidb size:" <<_dbNumber << endl); + + map mIp; + vector vIp; + string sIp(""); + string sIpAndPort(""); + + for (int i=0; i< _dbNumber; i++) + { + TC_DBConf tConf; + tConf.loadFromMap(g_pconf->getDomainMap("/tars/multidb/" + vDb[i])); + + _vsTbNamePre.push_back(g_pconf->get("/tars/multidb/" + vDb[i] + "", "t_stat_0" + TC_Common::tostr(i) + "_")); + + sIp = tConf._host; + + sIpAndPort = "ip:"; + sIpAndPort += tConf._host; + sIpAndPort += "|port:"; + sIpAndPort += TC_Common::tostr(tConf._port); + + _vIpAndPort.push_back(sIpAndPort); + + map::const_iterator iter = mIp.find(sIp); + if(iter == mIp.end()) + { + mIp.insert(map::value_type(sIp, 0)); + + _dbIpNum++; + + vector vIndex; + vIndex.push_back(i); + + _mIpHasDbInfo.insert(map >::value_type(sIp, vIndex)); + } + else + { + _mIpHasDbInfo[sIp].push_back(i); + } + + vIp.push_back(sIp); + + //默认值为1 + _vDbWeighted.push_back(TC_Common::strto(g_pconf->get("/tars/multidb/" + vDb[i] + "","1"))); + + TC_Mysql *pMysql = new TC_Mysql(); + pMysql->init(tConf); + + _vMysql.push_back(pMysql); + } + + //如果写db的线程小于db ip的个数,则设置db ip的个数为写db的线程数 + if(iInsertDbThreaad < _dbIpNum) + { + _dbIpNum = iInsertDbThreaad; + } + + TLOGDEBUG("StatDbManager init insert DB threadnum:" << _dbIpNum << endl); + + //设置每个db ip使用写db的线程下标,即每个写db线程负责写哪些ip的db数据 + size_t iIndex = 0; + map::iterator map_it = mIp.begin(); + while(map_it != mIp.end()) + { + map_it->second = iIndex; + ++iIndex; + + if(iIndex == _dbIpNum) + { + iIndex = 0; + } + + ++map_it; + } + + //设置每个db实例使用写db的线程下标,即每个写db线程负责写哪些db实例的数据 + for(size_t i = 0; i < vIp.size(); ++i) + { + map::const_iterator iter = mIp.find(vIp[i]); + if(iter != mIp.end()) + { + _mDbToIp.insert(map::value_type(i, iter->second)); + } + else + { + TLOGERROR("DbManager init DbToIp error ip:" << vIp[i] << endl); + } + } + + map >::iterator m_iter = _mIpHasDbInfo.begin(); + while(m_iter != _mIpHasDbInfo.end()) + { + vector &vDb = m_iter->second; + + FDLOG("CountStat") << "stat ip:" << ServerConfig::LocalIp << "|ip:" << m_iter->first << "|DbNum:" << vDb.size() << endl; + + ++m_iter; + } + + + TLOGDEBUG("StatDbManager init ok." << endl); +} +/////////////////////////////////////////////////////////// +StatDbManager::~StatDbManager() +{ + vector::iterator it = _vMysql.begin(); + while(it != _vMysql.end()) + { + if(*it) + { + delete *it; + } + ++it; + } +} +/////////////////////////////////////////////////////////// +size_t StatDbManager::getDbToIpIndex(size_t iIndex) +{ + map::const_iterator iter = _mDbToIp.find(iIndex); + if(iter != _mDbToIp.end()) + { + return iter->second; + } + return -1; +} +/////////////////////////////////////////////////////////// +bool StatDbManager::IsEnableWeighted() +{ + return _enableWeighted; +} +/////////////////////////////////////////////////////////// +string StatDbManager::getIpAndPort(size_t iDbIndex) +{ + assert(iDbIndex < _vIpAndPort.size()); + + return _vIpAndPort[iDbIndex]; +} +/////////////////////////////////////////////////////////// +void StatDbManager::getDbWeighted(int& iGcd,int& iMaxW,vector& vDbWeighted) +{ + vDbWeighted = _vDbWeighted; + + int gcd = 0; + int iMax = 0; + for(size_t i = 0;i < vDbWeighted.size(); i++) + { + gcd = getGcd(gcd,vDbWeighted[i]); + + if(vDbWeighted[i] > iMax) + { + iMax = vDbWeighted[i]; + } + } + + iGcd = gcd; + + iMaxW = iMax; +} +/////////////////////////////////////////////////////////// +int StatDbManager::getGcd (int a, int b) +{ + int c; + while(a != 0) + { + c = a; + a = b%a; + b = c; + } + + return b; +} +/////////////////////////////////////////////////////////// +int StatDbManager::genRandOrder() +{ + ostringstream os; + _vRandOrder.clear(); + srand((unsigned)time(NULL)); + int iValue = 0; + size_t i = 0; + while(1) + { + int iFound = 0; + iValue = rand()%(_dbNumber ); + for (i=0; i<_vRandOrder.size(); i++) + { + if (iValue == _vRandOrder[i]) + { + iFound = 1; + break; + } + } + if ( iFound == 0) + { + _vRandOrder.push_back(iValue); + } + else + { + continue; + } + if (_vRandOrder.size() == (size_t)_dbNumber ) + { + break; + } + } + + vector::iterator it = _vRandOrder.begin(); + while(it != _vRandOrder.end() ) + { + os << *it++ << " " ; + } + TLOGDEBUG("randorder: " << os.str() << endl); + return 0; + +} +/////////////////////////////////////////////////////////// +int StatDbManager::insert2Db(const StatMsg &statmsg, const string &sDate, const string &sFlag, const string &sTbNamePre, TC_Mysql *pMysql) +{ + int iCount = 0; + string sSql; + string strValues; + + string sTbName = (sTbNamePre != "" ? sTbNamePre : _tbNamePre); + sTbName += TC_Common::replace(sDate, "-", ""); + sTbName += sFlag.substr(0,_eCutType * 2); + + try + { + string sEscapeString = pMysql->escapeString(ServerConfig::LocalIp); + + creatTable(sTbName,pMysql); + + for (StatMsg::const_iterator it = statmsg.begin(); it != statmsg.end(); it++ ) + { + if(_terminate) + { + return -1; + } + + const StatMicMsgHead& head = it->first; + const StatMicMsgBody& body = it->second; + + string strIntervCount; + int iTemp = 0; + for (map::const_iterator it = body.intervalCount.begin();it != body.intervalCount.end();it++) + { + if (iTemp != 0) + { + strIntervCount += ","; + } + strIntervCount = strIntervCount; + strIntervCount += TC_Common::tostr(it->first); + strIntervCount += "|"; + strIntervCount += TC_Common::tostr(it->second); + iTemp++; + } + + int iAveTime = 0; + if ( body.count != 0 ) + { + iAveTime = body.totalRspTime/body.count; + iAveTime == 0?iAveTime=1:iAveTime=iAveTime; + } + + //组织sql语句 + strValues = " ('"; + strValues += sEscapeString; + strValues += "','"; + strValues += sDate; + strValues += "','"; + strValues += sFlag; + strValues += "','"; + strValues += pMysql->escapeString(head.masterName); + strValues += "','"; + strValues += pMysql->escapeString(head.slaveName); + strValues += "','"; + strValues += pMysql->escapeString(head.interfaceName); + strValues += "','"; + strValues += pMysql->escapeString(head.tarsVersion); + strValues += "','"; + strValues += pMysql->escapeString(head.masterIp); + strValues += "','"; + strValues += pMysql->escapeString(head.slaveIp); + strValues += "',"; + strValues += TC_Common::tostr( head.slavePort); + strValues += ","; + strValues += TC_Common::tostr( head.returnValue ); + strValues += ","; + strValues += TC_Common::tostr(body.count); + strValues += ","; + strValues += TC_Common::tostr(body.timeoutCount); + strValues += ","; + strValues += TC_Common::tostr(body.execCount); + strValues += ","; + strValues += TC_Common::tostr(body.totalRspTime); + strValues += ",'"; + strValues += strIntervCount; + strValues += "',"; + strValues += TC_Common::tostr(iAveTime); + strValues += ","; + strValues += TC_Common::tostr(body.maxRspTime); + strValues += ","; + strValues += TC_Common::tostr(body.minRspTime ) + ") "; + + if( iCount == 0 ) + { + sSql = "insert ignore into "; + sSql += sTbName; + sSql += " (source_id,f_date,f_tflag,master_name,slave_name,interface_name,tars_version,master_ip,slave_ip,slave_port,return_value, succ_count,timeout_count,exce_count,total_time,interv_count,ave_time,maxrsp_time, minrsp_time) values "; + sSql += strValues; + } + else + { + sSql += ","; + sSql += strValues; + } + + iCount ++; + if ( iCount >= _maxInsertCount ) + { + usleep(100); + pMysql->execute(sSql); + TLOGDEBUG("insert " << sTbName << " affected:" << iCount << endl); + + FDLOG("CountStat") << "stat ip:" << ServerConfig::LocalIp << "|insert " << sTbName << "|insert affected:" << iCount << "|mysql affected:" << pMysql->getAffectedRows() << endl; + iCount = 0; + } + } + + if ( iCount != 0 ) + { + pMysql->execute(sSql); + TLOGDEBUG("insert " << sTbName << " affected:" << iCount << endl); + FDLOG("CountStat") << "stat ip:" << ServerConfig::LocalIp << "|insert " << sTbName << "|insert affected:" << iCount << "|mysql affected:" << pMysql->getAffectedRows() << endl; + } + } + catch (TC_Mysql_Exception& ex) + { + string err = string (ex.what()); + if (std::string::npos == err.find( "Duplicate")) + { + creatTable(sTbName,pMysql); + } + //因为会输出1千条记录,这里做截取 + TLOGERROR("insert2Db exception: " << err.substr(0,64) << endl); + return 1; + } + catch (exception& ex) + { + TLOGERROR("insert2Db exception: " << ex.what() << endl); + return 1; + } + return 0; +} +/////////////////////////////////////////////////////////// +int StatDbManager::creatTable(const string &sTbName, TC_Mysql *_pstMql) +{ + string daytime = sTbName.substr(0, sTbName.length()- 2); // 去掉小时 + + if (_lastDayTimeTable == daytime) + { + TLOGDEBUG("StatDbManager::creatTable table " << sTbName << " exist." << endl); + return 0; + } + + int iRet = 0; + int hour = 0; + + for (hour=0; hour < 24; hour++) + { + char buf[3]; + snprintf(buf,sizeof(buf),"%.2d",hour); + string sName = daytime + string(buf); + iRet |= creatTb(sName, _pstMql); + } + + _lastDayTimeTable = daytime; + + return iRet; +} +/////////////////////////////////////////////////////////// +bool StatDbManager::IsdbTableExist(const string& sTbName,TC_Mysql *pMysql) +{ + try + { + TC_Mysql::MysqlData tTotalRecord = pMysql->queryRecord("show tables like '%"+sTbName+"%'"); + TLOGINFO(__FUNCTION__<<"|show tables like '%"+sTbName+"%|affected:"< 0) + { + return true; + } + else + { + return false; + } + + }catch(TC_Mysql_Exception& ex) + { + TLOGERROR("StatDbManager::IsdbTableExist exception: " << ex.what() << endl); + return false; + } +} +/////////////////////////////////////////////////////////// +int StatDbManager::creatTb(const string &sTbName,TC_Mysql *pMysql) +{ + try + { + if (!IsdbTableExist(sTbName,pMysql)) + { + string sSql = TC_Common::replace(_sql, "${TABLE}",sTbName); + TLOGINFO(sSql << endl); + pMysql->execute(sSql); + } + return 0; + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("StatDbManager::creatTb exception: " << ex.what() << endl); + return 1; + } +} +/////////////////////////////////////////////////////////// +int StatDbManager::creatEscTb(const string &sTbName, const string& sSql , TC_Mysql *pMysql) +{ + try + { + if (!IsdbTableExist(sTbName,pMysql)) + { + TLOGDEBUG(sSql << endl); + pMysql->execute(sSql); + + } + return 0; + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("exception: " << ex.what() << endl); + return 1; + } +} +/////////////////////////////////////////////////////////// +int StatDbManager::updateEcsStatus(const string &sLastTime,const string &sTbNamePre,TC_Mysql *pMysql) +{ + try + { + string sAppName = sTbNamePre != "" ? sTbNamePre : _tbNamePre; + string sCondition = "where appname='"; + sCondition += sAppName; + sCondition += "' and action=0"; + + TC_Mysql::RECORD_DATA rd; + rd["lasttime"] = make_pair(TC_Mysql::DB_STR, sLastTime); + + int iRet = pMysql->updateRecord("t_ecstatus", rd,sCondition); + + TLOGDEBUG("StatDbManager::updateEcsStatus iRet: " <getLastSQL()<< endl); + + if (iRet == 0 ) + { + rd["appname"] = make_pair(TC_Mysql::DB_STR, sAppName); + rd["checkint"] = make_pair(TC_Mysql::DB_INT, TC_Common::tostr(g_app.getInserInterv())); + rd["lasttime"] = make_pair(TC_Mysql::DB_STR, sLastTime); + iRet = pMysql->replaceRecord("t_ecstatus", rd); + } + + if (iRet != 1) + { + TLOGERROR("StatDbManager::updateEcsStatus erro: ret:" << iRet<<" "<getLastSQL()<< endl); + } + } + catch (TC_Mysql_Exception& ex) + { + string sql = _sqlStatus; + TLOGERROR("StatDbManager::updateEcsStatus exception: " << ex.what() << endl); + creatEscTb("t_ecstatus", sql, pMysql); + return 1; + } + return 0; +} +/////////////////////////////////////////////////////////// +int StatDbManager::insert2MultiDbs(int iIndex, const StatMsg &statmsg, const string &sDate, const string &sFlag) +{ + try + { + string sIp = ServerConfig::LocalIp; + + string sLastTime = sDate + " " + sFlag; + + string sTbNamePre = ""; + TC_Mysql * pMysql = NULL; + + sTbNamePre = _vsTbNamePre[iIndex]; + + pMysql = _vMysql[iIndex]; + + if (checkLastTime(sLastTime, sTbNamePre + sIp, pMysql) == 0) //=0,没有记录表示: 数据库记录的时间,比当前当前时间小 + { + TLOGDEBUG("begin insert to db " << getIpAndPort(iIndex) << endl); + + int64_t iBegin = tars::TC_TimeProvider::getInstance()->getNowMs(); + + if(insert2Db(statmsg, sDate, sFlag, sTbNamePre, pMysql) != 0) + { + if(_terminate) + { + return -1; + } + + if(insert2Db(statmsg ,sDate, sFlag, sTbNamePre, pMysql) != 0 ) + { + if(_terminate) + { + return -1; + } + + string sMsg("insert2Db_"); + sMsg += getIpAndPort(iIndex); + + sendAlarmSMS(sMsg); + } + else + { + if(updateEcsStatus(sLastTime, sTbNamePre + sIp, pMysql) != 0) + { + string sMsg("updateEcsStatus_"); + sMsg += getIpAndPort(iIndex); + + sendAlarmSMS(sMsg); + } + } + } + else + { + if(updateEcsStatus(sLastTime, sTbNamePre + sIp, pMysql) != 0) + { + string sMsg("updateEcsStatus_"); + sMsg += getIpAndPort(iIndex); + + sendAlarmSMS(sMsg); + } + } + + int64_t iEnd = tars::TC_TimeProvider::getInstance()->getNowMs(); + + TLOGDEBUG("insert|" << iIndex << "|" << getIpAndPort(iIndex) << "|" << sDate << "|" << sFlag << "|" << statmsg.size() << "|" << (iEnd - iBegin) << endl); + FDLOG("CountStat") << "stat ip:" << ServerConfig::LocalIp << "|insert|dbIndex:" << iIndex << "|" << getIpAndPort(iIndex) << "|date:" << sDate << "|tflag:" << sFlag + << "|records:" << statmsg.size() << "|timecost(ms):" << (iEnd - iBegin) << "|iBegin(ms):" << iBegin << "|iEnd(ms):" << iEnd << endl; + } + } + catch(TC_Mysql_Exception& ex) + { + TLOGERROR("StatDbManager::insert2MultiDbs TC_Mysql_Exception: " << ex.what() << endl); + } + catch(exception& ex) + { + TLOGERROR("StatDbManager::insert2MultiDbs exception: " << ex.what() << endl); + } + + return 0; +} + +/////////////////////////////////////////////////////////// +int StatDbManager::sendAlarmSMS(const string &sMsg) +{ + string errInfo = " ERROR:" + ServerConfig::LocalIp + "|" + sMsg + ":统计入库失败,请及时处理!"; + TARS_NOTIFY_ERROR(errInfo); + + TLOGERROR("TARS_NOTIFY_ERROR " << errInfo << endl); + + return 0; +} +/////////////////////////////////////////////////////////// +int StatDbManager::getDbNumber() +{ + return _dbNumber; +} +/////////////////////////////////////////////////////////// +int StatDbManager::checkLastTime(const string &sLastTime,const string &sTbNamePre,TC_Mysql *pMysql) +{ + int iRet = 0; + try + { + string sAppName = sTbNamePre != "" ? sTbNamePre : _tbNamePre; + string sCondition = "where appname='"; + sCondition += sAppName; + sCondition += "' and lasttime >= '"; + sCondition += sLastTime; + sCondition += "'" ; + + iRet = pMysql->getRecordCount("t_ecstatus", sCondition); + + TLOGDEBUG("StatDbManager::checkLastTime iRet: " <getLastSQL()<< endl); + } + catch (TC_Mysql_Exception& ex) + { + TLOGERROR("StatDbManager::checkLastTime exception: " << ex.what() << endl); + creatEscTb("t_ecstatus", _sqlStatus, pMysql); + return 0; + } + + return iRet; +} + diff --git a/StatServer/StatDbManager.h b/StatServer/StatDbManager.h new file mode 100644 index 00000000..4483ee59 --- /dev/null +++ b/StatServer/StatDbManager.h @@ -0,0 +1,155 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __DB_MANAGER_H_ +#define __DB_MANAGER_H_ + +#include "util/tc_common.h" +#include "util/tc_thread.h" +#include "util/tc_option.h" +#include "util/tc_file.h" +#include "util/tc_mysql.h" +#include "util/tc_config.h" +#include "servant/TarsLogger.h" +#include "jmem/jmem_hashmap.h" +#include "servant/StatF.h" +#include "StatHashMap.h" + +using namespace tars; + +class StatDbManager : public TC_Singleton,public TC_ThreadMutex +{ +public: + enum CutType + { + CUT_BY_DAY = 0, + CUT_BY_HOUR = 1, + CUT_BY_MINUTE = 2, + }; + +public: + /** + * + */ + StatDbManager(); + + ~StatDbManager(); + +public: + + int creatTb(const string &strTbName,TC_Mysql *pMysql = NULL); + + int creatTable(const string &sTbName, TC_Mysql *_pstMql); + + int creatEscTb(const string &sTbName, const string& sSql , TC_Mysql *pMysql); + + int insert2Db(const StatMsg &statmsg,const string &sDate,const string &sFlag,const string &sTbNamePre = "",TC_Mysql *pMysql = NULL); + + int updateEcsStatus(const string &sLastTime,const string &sTbNamePre = "",TC_Mysql *pMysql = NULL); + + int checkLastTime(const string &sLastTime,const string &sTbNamePre,TC_Mysql *pMysql); + + int insert2MultiDbs(int iIndex, const StatMsg &vStatmsg, const string &sDate, const string &sFlag); + + int sendAlarmSMS(const string &sMsg); + + int getDbNumber(); + + int genRandOrder(); + + /** + * 获取各个db的权重值,并返回所有权重的最大公约数值和最大权重 + * @param iGcd + * @param iMaxW + * @param vDbWeighted + */ + void getDbWeighted(int& iGcd,int& iMaxW,vector& vDbWeighted); + + bool IsEnableWeighted(); + + bool IsdbTableExist(const string& sTbName,TC_Mysql *pMysql); + + size_t getDbToIpIndex(size_t iIndex); + + size_t getDbIpNum() { return _dbIpNum; } + + string getIpAndPort(size_t iDbIndex); + + map >& getIpHasDbInfo() { return _mIpHasDbInfo; } + + void setITerminateFlag(bool bFlag) { _terminate = bFlag; } + +private: + + int getGcd (int a, int b); + +private: + + //入库时,停止的控制开关 + bool _terminate; + + //上次创建数据表的时间 + string _lastDayTimeTable; + + //创建表 + string _sql; + + //创建表t_ecstatus + string _sqlStatus; + + //表前缀 + string _tbNamePre; + + //一次最大插入条数 + int _maxInsertCount; + + //分表类型 + CutType _eCutType; + + //插入数据的mysql db信息 + vector _vMysql; + + //数据表前缀 + vector _vsTbNamePre; + + //db个数 + int _dbNumber; + + //随机值 + vector _vRandOrder; + + //各个db的权重值 + vector _vDbWeighted; + bool _enableWeighted; + + //db的ip个数 + size_t _dbIpNum; + + //设置每个db实例使用写db的线程下标,即每个写db线程负责写哪些db实例的数据 + map _mDbToIp; + + // + map > _mIpHasDbInfo; + + //打印日志使用 + vector _vIpAndPort; + + +}; + +#endif + + diff --git a/StatServer/StatHashMap.h b/StatServer/StatHashMap.h new file mode 100644 index 00000000..a74597a7 --- /dev/null +++ b/StatServer/StatHashMap.h @@ -0,0 +1,109 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __STAT_HASH_MAP_H_ +#define __STAT_HASH_MAP_H_ + +#include "servant/StatF.h" +#include "util/tc_common.h" +#include "util/tc_thread.h" +#include "util/tc_option.h" +#include "jmem/jmem_hashmap.h" +#include "util/tc_file.h" +#include "util/tc_config.h" +#include "servant/TarsLogger.h" + +using namespace tars; + +typedef TarsHashMap HashMap;//FileStorePolicy + +typedef std::map, __gnu_cxx::__pool_alloc > > StatMsg; + +class StatHashMap : public HashMap +{ +public: + /** + * 增加数据 + * @param Key + * @param Value + * + * @return int + */ + int add(const tars::StatMicMsgHead &head, const tars::StatMicMsgBody &body) + { + StatMicMsgBody stBody; + int ret = TC_HashMap::RT_OK; + tars::TarsOutputStream osk; + head.writeTo(osk); + string sk(osk.getBuffer(), osk.getLength()); + string sv; + time_t t = 0; + + { + + TC_LockT lock(ThreadLockPolicy::mutex()); + ret = this->_t.get(sk, sv,t); + + if (ret < 0) + { + return -1; + } + + //读取到数据了, 解包 + if (ret == TC_HashMap::RT_OK) + { + tars::TarsInputStream is; + is.setBuffer(sv.c_str(), sv.length()); + stBody.readFrom(is); + } + + stBody.count += body.count; + stBody.execCount += body.execCount; + stBody.timeoutCount += body.timeoutCount; + + for(map::const_iterator it = body.intervalCount.begin();it!= body.intervalCount.end();it++) + { + stBody.intervalCount[it->first] += it->second; + } + + stBody.totalRspTime += body.totalRspTime; + if(stBody.maxRspTime < body.maxRspTime) + { + stBody.maxRspTime = body.maxRspTime; + } + //非0最小值 + if( stBody.minRspTime == 0 || (stBody.minRspTime > body.minRspTime && body.minRspTime != 0)) + { + stBody.minRspTime = body.minRspTime; + } + + tars::TarsOutputStream osv; + stBody.writeTo(osv); + string stemp(osv.getBuffer(), osv.getLength()); + vector vtData; + + TLOGINFO("StatHashMap::add sk.length:" << sk.length() << " v.length:" << stemp.length() << endl); + + ret = this->_t.set(sk, stemp, true, vtData); + } + + return ret; + } +}; + +#endif + + diff --git a/StatServer/StatImp.cpp b/StatServer/StatImp.cpp new file mode 100644 index 00000000..04d55ef9 --- /dev/null +++ b/StatServer/StatImp.cpp @@ -0,0 +1,252 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "StatImp.h" +#include "StatServer.h" + +/////////////////////////////////////////////////////////// +TC_ThreadMutex StatImpThreadData::_mutex; +pthread_key_t StatImpThreadData::_key = 0; +size_t StatImpThreadData::_iNo=0; + +/////////////////////////////////////////////////////////// +StatImpThreadData::StatImpThreadData() +: _iThreadIndex(0) +{ +} +void StatImpThreadData::destructor(void* p) +{ + StatImpThreadData * pSptd = (StatImpThreadData*)p; + if(pSptd) + { + delete pSptd; + pSptd = NULL; + } +} + +StatImpThreadData * StatImpThreadData::getData() +{ + if(_key == 0) + { + TC_LockT lock(_mutex); + if(_key == 0) + { + int iRet = ::pthread_key_create(&_key, StatImpThreadData::destructor); + + if (iRet != 0) + { + TLOGERROR("StatImpThreadData pthread_key_create fail:"<< errno << ":" << strerror(errno) << endl); + return NULL; + } + } + } + + StatImpThreadData * pSptd = (StatImpThreadData*)pthread_getspecific(_key); + + if(!pSptd) + { + TC_LockT lock(_mutex); + + pSptd = new StatImpThreadData(); + pSptd->_iThreadIndex = _iNo; + ++_iNo; + + int iRet = pthread_setspecific(_key, (void *)pSptd); + + assert(iRet == 0); + } + return pSptd; +} + +////////////////////////////////////////////////////////// +void StatImp::initialize() +{ + StatImpThreadData * td = StatImpThreadData::getData(); + + if(td) + { + _threadIndex = td->_iThreadIndex; + } + else + { + _threadIndex = 0; + TLOGERROR("StatImp::initialize StatImpThreadData::getData error." << endl); + } +} + +/////////////////////////////////////////////////////////// +// +int StatImp::reportMicMsg( const map& statmsg,bool bFromClient, tars::TarsCurrentPtr current ) +{ + TLOGINFO("report---------------------------------access size:" << statmsg.size() << "|bFromClient:" <::const_iterator it = statmsg.begin(); it != statmsg.end(); it++ ) + { + StatMicMsgHead head = it->first; + const StatMicMsgBody &body = it->second; + + if(bFromClient) + { + head.masterIp = current->getIp(); //以前是自己获取主调ip,现在从proxy直接 + + head.slaveName = getSlaveName(head.slaveName); + } + else + { + head.slaveIp = current->getIp();//现在从proxy直接 + } + + string sMasterName = head.masterName; + string::size_type pos = sMasterName.find("@"); + if (pos != string::npos) + { + head.masterName = sMasterName.substr(0, pos); + head.tarsVersion = sMasterName.substr(pos+1); + } + + map::iterator it_vip; + it_vip = g_app.getVirtualMasterIp().find(getSlaveName(head.slaveName)); + if( it_vip != g_app.getVirtualMasterIp().end()) + { + head.masterIp = it_vip->second; //按 slaveName来匹配,填入假的主调ip,减小入库数据量 + } + + //如果不是info等级的日志级别,就别往里走了 + ostringstream os; + if(LOG->IsNeedLog(TarsRollLogger::INFO_LOG)) + { + os.str(""); + head.displaySimple(os); + body.displaySimple(os); + } + + //三个数据都为0时不入库 + if(body.count == 0 && body.execCount == 0 && body.timeoutCount == 0) + { + TLOGINFO(os.str()<<"|zero"< &msg,tars::TarsCurrentPtr current ) +{ + TLOGINFO("sample---------------------------------access size:" << msg.size() << endl); + + for(unsigned i=0; igetIp(); + + ostringstream os; + sample.displaySimple(os); + FDLOG()< >& mBuffer = g_app.getBuffer(); + map >::iterator iter = mBuffer.find(iBufferIndex); + iter->second[iIndex] = TNOW; + + dump2file(); + + iBufferIndex = g_app.getSelectBufferIndex(); + + string sKey = head.slaveName; + sKey += head.masterName; + sKey += head.interfaceName; + sKey += head.masterIp; + sKey += head.slaveIp; + + int iHashKey = _hashf(sKey) % g_app.getBuffNum(); + + StatHashMap *pHashMap = g_app.getHashMapBuff(iBufferIndex, iHashKey); + + ////////////////////////////////////////////////////////////////////////////////////// + + float rate = (pHashMap->getMapHead()._iUsedChunk) * 1.0/pHashMap->allBlockChunkCount(); + + if(rate >0.9) + { + TLOGERROR("StatImp::addHashMap hashmap will full|_iMemSize:" << pHashMap->getMapHead()._iMemSize << endl); + FDLOG("HashMap")<<"StatImp::addHashMap hashmap will full|_iMemSize:" << pHashMap->getMapHead()._iMemSize << endl; + return -1; + } + + int iRet = pHashMap->add(head, body); + if(iRet != 0) + { + TLOGDEBUG("StatImp::addHashMap set g_hashmap recourd erro|" << iRet << endl); + return iRet; + } + return iRet; +} + +/////////////////////////////////////////////////////////// +string StatImp::getSlaveName(const string& sSlaveName) +{ + return sSlaveName; +} + +void StatImp::dump2file() +{ + static string g_sDate; + static string g_sFlag; + static time_t g_tLastDumpTime = 0; + + time_t tTimeNow = TC_TimeProvider::getInstance()->getNow(); + time_t tTimeInterv = g_app.getInserInterv() *60;//second + + if(g_tLastDumpTime == 0) + { + g_app.getTimeInfo(g_tLastDumpTime,g_sDate,g_sFlag); + } + + if(tTimeNow - g_tLastDumpTime > tTimeInterv) + { + static TC_ThreadLock g_mutex; + TC_ThreadLock::Lock lock( g_mutex ); + if(tTimeNow - g_tLastDumpTime > tTimeInterv) + { + g_app.getTimeInfo(g_tLastDumpTime,g_sDate,g_sFlag); + + int iSelectBuffer = g_app.getSelectBufferIndex(); + iSelectBuffer = !iSelectBuffer; + + g_app.setSelectBufferIndex(iSelectBuffer); + + TLOGDEBUG("StatImp::dump2file select buffer:" << iSelectBuffer << "|TimeInterv:" << tTimeInterv << "|now:" << tTimeNow << "|last:" << g_tLastDumpTime << endl); + FDLOG("CountStat") << "stat ip:" << ServerConfig::LocalIp << "|StatImp::dump2file select buffer:" << iSelectBuffer << "|TimeInterv:" << tTimeInterv << "|now:" << tTimeNow << "|last:" << g_tLastDumpTime << endl; + } + } +} diff --git a/StatServer/StatImp.h b/StatServer/StatImp.h new file mode 100644 index 00000000..955d6c7e --- /dev/null +++ b/StatServer/StatImp.h @@ -0,0 +1,125 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __STAT_IMP_H_ +#define __STAT_IMP_H_ + +#include +#include "util/tc_common.h" +#include "util/tc_thread.h" +#include "util/tc_option.h" +#include "util/tc_file.h" +#include "util/tc_mysql.h" +#include "util/tc_config.h" +#include "util/tc_hash_fun.h" +#include "servant/TarsLogger.h" +#include "jmem/jmem_hashmap.h" +#include "servant/StatF.h" +#include "StatHashMap.h" + +using namespace tars; + +class StatImpThreadData : public TC_ThreadPool::ThreadData +{ +public: + static TC_ThreadMutex _mutex; //全局互斥锁 + static pthread_key_t _key; //线程私有数据key + static size_t _iNo; + + /** + * 构造函数 + */ + StatImpThreadData(); + + /** + * 数据资源释放 + * @param p + */ + static void destructor(void* p); + + /** + * 获取线程数据,没有的话会自动创建 + * @return ServantProxyThreadData* + */ + static StatImpThreadData * getData(); + +public: + size_t _iThreadIndex; +}; + +class StatImp : public StatF,public TC_ThreadLock +{ +public: + /** + * + */ + StatImp() + : _hashf(tars::hash()) + , _threadIndex(0) + { + }; + + ~StatImp() + { + }; + + /** + * 初始化 + * + * @return int + */ + virtual void initialize(); + + /** + * 退出 + */ + virtual void destroy() + { + }; + + /** + * 上报模块间调用信息 + * @param statmsg, 上报信息 + * @return int, 返回0表示成功 + */ + virtual int reportMicMsg( const map& statmsg, bool bFromClient, tars::TarsCurrentPtr current ); + + /** + * 上报模块间调用采样信息 + * @param sample, 上报信息 + * @return int, 返回0表示成功 + */ + virtual int reportSampleMsg(const vector &msg,tars::TarsCurrentPtr current ); + + using hash_functor = std::function; + +protected: + + int addHashMap(const StatMicMsgHead &head, const StatMicMsgBody &body); + +private: + void dump2file(); + + string getSlaveName(const string& sSlaveName); + +private: + hash_functor _hashf; + size_t _threadIndex; +}; + +#endif + + diff --git a/StatServer/StatServer.cpp b/StatServer/StatServer.cpp new file mode 100644 index 00000000..8a17e967 --- /dev/null +++ b/StatServer/StatServer.cpp @@ -0,0 +1,325 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "StatServer.h" +#include "servant/AppCache.h" +#include "StatImp.h" + +void StatServer::initialize() +{ + try + { + //关闭远程日志 + TarsTimeLogger::getInstance()->enableRemote("", false); + + //增加对象 + addServant( ServerConfig::Application + "." + ServerConfig::ServerName +".StatObj" ); + + _iInsertInterval = TC_Common::strto(g_pconf->get("/tars/hashmap","5")); + if(_iInsertInterval < 5) + { + _iInsertInterval = 5; + } + + //获取业务线程个数 + string sAdapter = ServerConfig::Application + "." + ServerConfig::ServerName + ".StatObjAdapter"; + string sHandleNum = "/tars/application/server/"; + sHandleNum += sAdapter; + sHandleNum += ""; + + int iHandleNum = TC_Common::strto(g_pconf->get(sHandleNum, "20")); + vector vec; + vec.resize(iHandleNum); + for(size_t i =0; i < vec.size(); ++i) + { + vec[i] = 0; + } + + _vBuffer[0]=vec; + _vBuffer[1]=vec; + + TLOGDEBUG("StatServer::initialize iHandleNum:" << iHandleNum<< endl); + + initHashMap(); + + string s(""); + _iSelectBuffer = getSelectBufferFromFlag(s); + + TLOGDEBUG("StatServer::initialize iSelectBuffer:" << _iSelectBuffer<< endl); + + vector vIpGroup = g_pconf->getDomainKey("/tars/masteripgroup"); + for (unsigned i = 0; i < vIpGroup.size(); i++) + { + vector vOneGroup = TC_Common::sepstr(vIpGroup[i], ";", true); + if (vOneGroup.size() < 2) + { + TLOGERROR("StatImp::initialize wrong masterip:" << vIpGroup[i] << endl); + continue; + } + _mVirtualMasterIp[vOneGroup[0]] = vOneGroup[1]; + } + + _sRandOrder = AppCache::getInstance()->get("RandOrder"); + TLOGDEBUG("StatImp::initialize randorder:" << _sRandOrder << endl); + + _pReapSSDThread = new ReapSSDThread(); + _pReapSSDThread->start(); + + TARS_ADD_ADMIN_CMD_PREFIX("tars.tarsstat.randorder", StatServer::cmdSetRandOrder); + } + catch ( exception& ex ) + { + TLOGERROR("StatServer::initialize catch exception:" << ex.what() << endl); + exit( 0 ); + } + catch ( ... ) + { + TLOGERROR("StatServer::initialize unknow exception catched" << endl); + exit( 0 ); + } +} + +map& StatServer::getVirtualMasterIp(void) +{ + return _mVirtualMasterIp; +} + +string StatServer::getRandOrder(void) +{ + return _sRandOrder; +} + +string StatServer::getClonePath(void) +{ + return _sClonePath; +} + +int StatServer::getInserInterv(void) +{ + return _iInsertInterval; +} + +bool StatServer::getSelectBuffer(int iIndex, int64_t iInterval) +{ + int64_t iNow = TNOW; + bool bFlag = true; + vector &vBuffer = _vBuffer[iIndex]; + + for(vector::size_type i=0; i != vBuffer.size(); i++) + { + //if(vBuffer[i] != 0 && (iNow - vBuffer[i]) > iInterval) + if((iNow - vBuffer[i]) < iInterval) + { + bFlag = false; + } + } + + if(bFlag) + { + return true; + } + + return false; +} +int StatServer::getSelectBufferFromFlag(const string& sFlag) +{ + if(sFlag.length()!=0) + { + return (TC_Common::strto(sFlag.substr(2,2))/_iInsertInterval)%2; + } + else + { + time_t tTime=0; + string sDate="",flag=""; + getTimeInfo(tTime,sDate,flag); + return (TC_Common::strto(flag.substr(2,2))/_iInsertInterval)%2; + } +} +bool StatServer::cmdSetRandOrder(const string& command, const string& params, string& result) +{ + try + { + TLOGINFO("StatServer::cmdSetRandOrder:" << command << " " << params << endl); + + _sRandOrder = params; + + result = "set RandOrder [" + _sRandOrder + "] ok"; + + AppCache::getInstance()->set("RandOrder",_sRandOrder); + } + catch (exception &ex) + { + result = ex.what(); + } + return true; +} + +void StatServer::initHashMap() +{ + TLOGDEBUG("StatServer::initHashMap begin" << endl); + + int iHashMapNum = TC_Common::strto(g_pconf->get("/tars/hashmap","1")); + + _iBuffNum = iHashMapNum; + + _hashmap = new StatHashMap *[2]; + + for(int k = 0; k < 2; ++k) + { + _hashmap[k] = new StatHashMap[iHashMapNum](); + } + + int iMinBlock = TC_Common::strto(g_pconf->get("/tars/hashmap","128")); + int iMaxBlock = TC_Common::strto(g_pconf->get("/tars/hashmap","256")); + float iFactor = TC_Common::strto(g_pconf->get("/tars/hashmap","2")); + int iSize = TC_Common::toSize(g_pconf->get("/tars/hashmap"), 1024*1024*256); + + _sClonePath = ServerConfig::DataPath + "/" + g_pconf->get("/tars/hashmap","clone"); + + if(!TC_File::makeDirRecursive(_sClonePath)) + { + TLOGERROR("cannot create hashmap file " << _sClonePath << endl); + exit(0); + } + + TLOGDEBUG("StatServer::initHashMap init multi hashmap begin..." << endl); + + char a[26]; + int iChar = 0; + for(int n = 0; n < 26; n++) + { + a[n] = 'a' + n; + } + + for(int i = 0; i < 2; ++i) + { + for(int k = 0; k < iHashMapNum; ++k) + { + string sFileConf("/tars/hashmapget(sFileConf, sFileDefault); + + string sPath = TC_File::extractFilePath(sHashMapFile); + + if(!TC_File::makeDirRecursive(sPath)) + { + TLOGERROR("cannot create hashmap file " << sPath << endl); + exit(0); + } + + try + { + TLOGINFO("initDataBlockSize size: " << iMinBlock << ", " << iMaxBlock << ", " << iFactor << endl); + + _hashmap[i][k].initDataBlockSize(iMinBlock,iMaxBlock,iFactor); + + if(TC_File::isFileExist(sHashMapFile)) + { + iSize = TC_File::getFileSize(sHashMapFile); + } + else + { + int fd = open(sHashMapFile.c_str(), O_CREAT|O_EXCL|O_RDWR, 0666); + if(fd == -1) + { + if(errno != EEXIST) + { + throw TC_Exception("open1 file '" + sHashMapFile + "' error", errno); + } + else + { + fd = open(sHashMapFile.c_str(), O_CREAT|O_RDWR, 0666); + if(fd == -1) + { + throw TC_Exception("open2 file '" + sHashMapFile + "' error", errno); + } + } + } + + lseek(fd, iSize-1, SEEK_SET); + write(fd,"\0",1); + if(fd != -1) + { + close(fd); + } + } + + key_t key = ftok(sHashMapFile.c_str(), a[iChar%26]); + + iChar++; + + TLOGDEBUG("init hash mem,shm key: 0x" << hex << key << dec << endl); + + //_hashmap[i][k].initStore( sHashMapFile.c_str(), iSize ); + _hashmap[i][k].initStore(key, iSize); + _hashmap[i][k].setAutoErase(false); + + TLOGINFO("\n" << _hashmap[i][k].desc() << endl); + } + catch(TC_HashMap_Exception &e) + { + TC_File::removeFile(sHashMapFile,false); + throw runtime_error(e.what()); + } + + } + } + + TLOGDEBUG("StatServer::initHashMap init multi hashmap end..." << endl); +} + +void StatServer::destroyApp() +{ + if(_pReapSSDThread) + { + delete _pReapSSDThread; + _pReapSSDThread = NULL; + } + + for(int i = 0; i < 2; ++i) + { + delete [] _hashmap[i]; + } + + delete [] _hashmap; + + TLOGDEBUG("StatServer::destroyApp ok" << endl); +} + +void StatServer::getTimeInfo(time_t &tTime,string &sDate,string &sFlag) +{ + string sTime,sHour,sMinute; + time_t t = TC_TimeProvider::getInstance()->getNow(); + t = (t/(_iInsertInterval*60))*_iInsertInterval*60; //要求必须为loadIntev整数倍 + tTime = t; + t = (t%3600 == 0?t-60:t); //要求将9点写作0860 + sTime = TC_Common::tm2str(t,"%Y%m%d%H%M"); + sDate = sTime.substr(0,8); + sHour = sTime.substr(8,2); + sMinute = sTime.substr(10,2); + sFlag = sHour + (sMinute=="59"?"60":sMinute); //要求将9点写作0860 +} + + diff --git a/StatServer/StatServer.h b/StatServer/StatServer.h new file mode 100644 index 00000000..60027814 --- /dev/null +++ b/StatServer/StatServer.h @@ -0,0 +1,101 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __STAT_SERVER_H_ +#define __STAT_SERVER_H_ + +#include "servant/Application.h" +#include "servant/StatF.h" +#include "StatHashMap.h" +#include "ReapSSDThread.h" + +using namespace tars; + +class StatServer : public Application +{ +protected: + /** + * 初始化, 只会进程调用一次 + */ + virtual void initialize(); + + /** + * 析够, 每个进程都会调用一次 + */ + virtual void destroyApp(); + +public: + + void getTimeInfo(time_t &tTime,string &sDate,string &sFlag); + + bool cmdSetRandOrder(const string& command, const string& params, string& result); + + //获取主调虚拟ip映射 + map& getVirtualMasterIp(void); + + string getRandOrder(void); + + string getClonePath(void); + + int getInserInterv(void); + + map >& getBuffer(){ return _vBuffer; } + + bool getSelectBuffer(int iIndex, int64_t iInterval); + + int getSelectBufferFromFlag(const string& sFlag); + + int getSelectBufferIndex() { return _iSelectBuffer; } + + void setSelectBufferIndex(int iIndex) { _iSelectBuffer = iIndex; } + + StatHashMap * getHashMapBuff(int iIndex, int iBuffer) { return &(_hashmap[iIndex][iBuffer]); } + + int getBuffNum() { return _iBuffNum; } + +private: + void initHashMap(); + +private: + + ReapSSDThread* _pReapSSDThread; + + //主调虚拟ip配置 + map _mVirtualMasterIp; + + // 随机入库开关 + string _sRandOrder; + + //数据换存目录 + string _sClonePath; + + //数据库插入间隔,单位分钟 + int _iInsertInterval; + + //双buffer机制 + map > _vBuffer; + + int _iSelectBuffer; + + StatHashMap **_hashmap; + + int _iBuffNum; +}; + +extern TC_Config* g_pconf; +extern StatServer g_app; + +#endif diff --git a/StatServer/main.cpp b/StatServer/main.cpp new file mode 100644 index 00000000..92e8cd84 --- /dev/null +++ b/StatServer/main.cpp @@ -0,0 +1,41 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "StatServer.h" +#include + +using namespace std; + +TC_Config* g_pconf; +StatServer g_app; + +int main( int argc, char* argv[] ) +{ + try + { + g_pconf = &g_app.getConfig(); + g_app.main( argc, argv ); + g_app.waitForShutdown(); + } + catch ( exception& ex ) + { + cout << ex.what() << endl; + } + + return 0; +} + + diff --git a/build/README.md b/build/README.md new file mode 100644 index 00000000..67599697 --- /dev/null +++ b/build/README.md @@ -0,0 +1,18 @@ +The scripts of buiding Tars framework project + +download all associated projects firstly +``` +build.sh prepare +``` +compile +``` +build.sh all +``` +cleanup +``` +build.sh cleanall +``` +install +``` +build.sh install +``` diff --git a/build/build.sh b/build/build.sh new file mode 100755 index 00000000..6ff0e92d --- /dev/null +++ b/build/build.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +ARGS=$1 + +if [ $# -lt 1 ]; then + ARGS="help" +fi + +BASEPATH=$(cd `dirname $0`; pwd) + +case $ARGS in + prepare) + cd ..; git submodule update --init --recursive + ;; + all) + cd $BASEPATH; cmake ..; make + ;; + cleanall) + cd $BASEPATH; make clean; ls | grep -v build.sh | grep -v README.md | xargs rm -rf + ;; + install) + cd $BASEPATH; make install + ;; + help|*) + echo "Usage:" + echo "$0 help: view help info." + echo "$0 all: build all target" + echo "$0 install: install framework" + echo "$0 cleanall: remove all temp file" + ;; +esac + + diff --git a/conf/tars.default b/conf/tars.default new file mode 100644 index 00000000..ad084cf2 --- /dev/null +++ b/conf/tars.default @@ -0,0 +1,33 @@ + + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + stat=tars.tarsstat.StatObj + property=tars.tarsproperty.PropertyObj + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + deactivating-timeout=3000 + logLevel=DEBUG + + + diff --git a/conf/tars.tarsconfig b/conf/tars.tarsconfig new file mode 100644 index 00000000..716ec47d --- /dev/null +++ b/conf/tars.tarsconfig @@ -0,0 +1,39 @@ + + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + deactivating-timeout=3000 + logLevel=DEBUG + + + + charset=utf8 + dbhost=db.tars.com + dbname=db_tars + dbpass=tars2015 + dbport=3306 + dbuser=tars + + \ No newline at end of file diff --git a/conf/tars.tarsjava.default b/conf/tars.tarsjava.default new file mode 100644 index 00000000..7ccdc2a4 --- /dev/null +++ b/conf/tars.tarsjava.default @@ -0,0 +1,44 @@ + + + enableset=${enableset} + setdivision=${setdivision} + + asyncthread=${asyncthread} + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + stat=tars.tarsstat.StatObj + property=tars.tarsproperty.PropertyObj + report-interval=60000 + modulename=${modulename} + sample-rate=100000 + max-sample-count=50 + + + deactivating-timeout=3000 + logLevel=DEBUG + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + loglevel=DEBUG + logsize=15M + log=tars.tarslog.LogObj + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + mainclass=com.qq.cloud.tars.server.startup.Main + classpath=${basepath}/conf:${basepath}/lib + jvmparams=-Dcom.sun.management.jmxremote.ssl\=false -Dcom.sun.management.jmxremote.authenticate\=false -Xms2000m -Xmx2000m -Xmn1000m -Xss1000k -XX:PermSize\=128M -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction\=60 -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps -XX:+CMSParallelRemarkEnabled -XX:+CMSScavengeBeforeRemark -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction\=0 -verbosegc -XX:+PrintGCDetails -XX:ErrorFile\=${logpath}/${app}/${server}/jvm_error.log + sessiontimeout=120000 + sessioncheckinterval=60000 + tcpnodelay=true + udpbuffersize=8192 + charsetname=UTF-8 + backupfiles=bak1;bak2;bak3;conf + + + \ No newline at end of file diff --git a/conf/tars.tarslog b/conf/tars.tarslog new file mode 100644 index 00000000..f6567764 --- /dev/null +++ b/conf/tars.tarslog @@ -0,0 +1,40 @@ + + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + stat=tars.tarsstat.StatObj + property=tars.tarsproperty.PropertyObj + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=100000000 + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + deactivating-timeout=3000 + logLevel=ERROR + + + + logpath=/usr/local/app/tars/remote_app_log + logthread=10 + + hour=xx + + + \ No newline at end of file diff --git a/conf/tars.tarsnotify b/conf/tars.tarsnotify new file mode 100644 index 00000000..af73c2db --- /dev/null +++ b/conf/tars.tarsnotify @@ -0,0 +1,49 @@ + + sql=CREATE TABLE `${TABLE}` ( `id` int(11) NOT NULL AUTO_INCREMENT, `application` varchar(128) DEFAULT '', `server_name` varchar(128) DEFAULT NULL, `container_name` varchar(128) DEFAULT '' , `node_name` varchar(128) NOT NULL DEFAULT '', `set_name` varchar(16) DEFAULT NULL, `set_area` varchar(16) DEFAULT NULL, `set_group` varchar(16) DEFAULT NULL, `server_id` varchar(100) DEFAULT NULL, `thread_id` varchar(20) DEFAULT NULL, `command` varchar(50) DEFAULT NULL, `result` text, `notifytime` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `index_name` (`server_name`), KEY `servernoticetime_i_1` (`notifytime`), KEY `indx_1_server_id` (`server_id`), KEY `query_index` (`application`,`server_name`,`node_name`,`set_name`,`set_area`,`set_group`) ) ENGINE\=InnoDB DEFAULT CHARSET\=utf8 + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + deactivating-timeout=3000 + logLevel=DEBUG + + + + charset=utf8 + dbhost=db.tars.com + dbpass=tars2015 + dbport=3306 + dbuser=tars + dbname=db_tars + + + min_block=50 + max_block=200 + factor=1.5 + file_path=./notify + file_size=50000000 + max_page_num=30 + max_page_size=20 + + \ No newline at end of file diff --git a/conf/tars.tarspatch b/conf/tars.tarspatch new file mode 100644 index 00000000..8fdc6e81 --- /dev/null +++ b/conf/tars.tarspatch @@ -0,0 +1,34 @@ + + directory=/usr/local/app/patchs/tars + uploadDirectory=/usr/local/app/patchs/tars.upload + size=100M + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + deactivating-timeout=3000 + logLevel=DEBUG + + + \ No newline at end of file diff --git a/conf/tars.tarsproperty b/conf/tars.tarsproperty new file mode 100644 index 00000000..bfabaf12 --- /dev/null +++ b/conf/tars.tarsproperty @@ -0,0 +1,76 @@ + + sql=CREATE TABLE `${TABLE}` (`stattime` timestamp NOT NULL default CURRENT_TIMESTAMP,`f_date` date NOT NULL default '1970-01-01', `f_tflag` varchar(8) NOT NULL default '',`master_name` varchar(128) NOT NULL default '',`master_ip` varchar(16) default NULL,`property_name` varchar(100) default NULL,`set_name` varchar(15) NOT NULL default '',`set_area` varchar(15) NOT NULL default '',`set_id` varchar(15) NOT NULL default '',`policy` varchar(20) default NULL,`value` varchar(255) default NULL, KEY (`f_date`,`f_tflag`,`master_name`,`master_ip`,`property_name`,`policy`),KEY `IDX_MASTER_NAME` (`master_name`),KEY `IDX_MASTER_IP` (`master_ip`),KEY `IDX_TIME` (`stattime`)) ENGINE\=Innodb + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + deactivating-timeout=3000 + logLevel=DEBUG + + + + logpath=/usr/local/app/tars/remote_app_log + logthread=10 + + + charset + dbhost=db.tars.com + dbname=tars + dbport=3306 + dbuser=tars + dbpass=tars2015 + + + + dbhost=db.tars.com + dbname=tars_property + tbname=tars_property_ + dbuser=tars + dbpass=tars2015 + dbport=3306 + charset=utf8 + + + dbhost=db.tars.com + dbname=tars_property + tbname=tars_property_ + dbuser=tars + dbpass=tars2015 + dbport=3306 + charset=utf8 + + + + factor=1.5 + file=hashmap.txt + insertInterval=5 + maxBlock=200 + minBlock=100 + size=10M + + + Interval=10 + sql=insert ignore into t_master_property select master_name, property_name, policy from ${TABLE} group by master_name, property_name, policy; + + \ No newline at end of file diff --git a/conf/tars.tarsstat b/conf/tars.tarsstat new file mode 100644 index 00000000..2269f8ae --- /dev/null +++ b/conf/tars.tarsstat @@ -0,0 +1,61 @@ + + sql=CREATE TABLE `${TABLE}`( `stattime` timestamp NOT NULL default CURRENT_TIMESTAMP,`f_date` date NOT NULL default '1970-01-01', `f_tflag` varchar(8) NOT NULL default '',`source_id` varchar(15) default NULL,`master_name` varchar(64) default NULL,`slave_name` varchar(64) default NULL,`interface_name` varchar(64) default NULL,`tars_version` varchar(16) NOT NULL default '',`master_ip` varchar(15) default NULL,`slave_ip` varchar(21) default NULL,`slave_port` int(10) default NULL,`return_value` int(11) default NULL,`succ_count` int(10) unsigned default NULL,`timeout_count` int(10) unsigned default NULL,`exce_count` int(10) unsigned default NULL,`interv_count` varchar(128) default NULL,`total_time` bigint(20) unsigned default NULL,`ave_time` int(10) unsigned default NULL,`maxrsp_time` int(10) unsigned default NULL,`minrsp_time` int(10) unsigned default NULL,PRIMARY KEY (`source_id`,`f_date`,`f_tflag`,`master_name`,`slave_name`,`interface_name`,`master_ip`,`slave_ip`,`slave_port`,`return_value`,`tars_version`),KEY `IDX_TIME` (`stattime`),KEY `IDC_MASTER` (`master_name`),KEY `IDX_INTERFACENAME` (`interface_name`),KEY `IDX_FLAGSLAVE` (`f_tflag`,`slave_name`), KEY `IDX_SLAVEIP` (`slave_ip`),KEY `IDX_SLAVE` (`slave_name`),KEY `IDX_RETVALUE` (`return_value`),KEY `IDX_MASTER_IP` (`master_ip`),KEY `IDX_F_DATE` (`f_date`)) ENGINE\=MyISAM DEFAULT CHARSET\=utf8 + enWeighted=1 + useolddatabase=0 + time_out=600 + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + deactivating-timeout=3000 + logLevel=DEBUG + + + + tars.tarsstat;1.1.1.1 + + + masterfile=hashmap_master.txt + slavefile=hashmap_slave.txt + insertInterval=5 + enableStatCount=0 + size=8M + countsize=1M + + + interval=5 + insertDbThreadNum=4 + + + + dbhost=db.tars.com + dbname=tars_stat + tbname=tars_stat_ + dbuser=tars + dbpass=tars2015 + dbport=3306 + charset=utf8 + + + \ No newline at end of file diff --git a/deploy/tarsAdminRegistry/conf/adminregistry.conf b/deploy/tarsAdminRegistry/conf/adminregistry.conf new file mode 100644 index 00000000..f4955308 --- /dev/null +++ b/deploy/tarsAdminRegistry/conf/adminregistry.conf @@ -0,0 +1,62 @@ + + + enableset=n + setdivision=NULL + + app=tars + server=tarsAdminRegistry + localip=192.168.2.131 + basepath=/usr/local/app/tars/bin + datapath=/usr/local/app/tars/tarsnode/data/tars.tarsAdminRegistry/data + logpath=/usr/local/app/tars/app_log + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + deactivating-timeout=2000 + logLevel=DEBUG + + allow + endpoint=tcp -h registry.tars.com -p 12000 -t 60000 + handlegroup=tars.tarsAdminRegistry.AdminRegObjAdapter + maxconns=1024 + protocol=tars + queuecap=10000 + queuetimeout=60000 + servant=tars.tarsAdminRegistry.AdminRegObj + threads=5 + + + + locator=tars.tarsregistry.QueryObj@tcp -h registry.tars.com -p 17890 + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=3 + modulename=tars.tarsAdminRegistry + + + + AdminRegObjName=tars.tarsAdminRegistry.AdminRegObj + patchServerObj=tars.tarspatch.PatchObj + + + dbhost=db.tars.com + dbname=db_tars + dbuser=tars + dbpass=tars2015 + dbport=3306 + charset=utf8 + dbflag=CLIENT_MULTI_STATEMENTS + + + defaultTemplate=tars.tarsnode + sync_node_timeout=4000 + + + updateHeartInterval=15 + reigistryTimeout=150 + + diff --git a/deploy/tarsAdminRegistry/util/execute.sh b/deploy/tarsAdminRegistry/util/execute.sh new file mode 100644 index 00000000..db32a96d --- /dev/null +++ b/deploy/tarsAdminRegistry/util/execute.sh @@ -0,0 +1,22 @@ +#!/bin/sh +ulimit -a +bin="/usr/local/app/tars/tarsAdminRegistry/bin/tarsAdminRegistry" + +PID=`ps -eopid,cmd | grep "$bin"| grep "tarsAdminRegistry" | grep -v "grep" |awk '{print $1}'` + +echo $PID + +if [ "$PID" != "" ]; then + kill -9 $PID + echo "kill -9 $PID" +fi +ulimit -c unlimited + +CONFIG=/usr/local/app/tars/tarsnode/data/tars.tarsAdminRegistry/conf/tars.tarsAdminRegistry.conf + +if [ ! -f $CONFIG ]; then + CONFIG=/usr/local/app/tars/tarsAdminRegistry/conf/adminregistry.conf +fi + +$bin --config=$CONFIG & + diff --git a/deploy/tarsAdminRegistry/util/start.sh b/deploy/tarsAdminRegistry/util/start.sh new file mode 100644 index 00000000..b85cf7ad --- /dev/null +++ b/deploy/tarsAdminRegistry/util/start.sh @@ -0,0 +1,2 @@ +#!/bin/sh +sh /usr/local/app/tars/tarsAdminRegistry/util/execute.sh diff --git a/deploy/tarsAdminRegistry/util/stop.sh b/deploy/tarsAdminRegistry/util/stop.sh new file mode 100644 index 00000000..a28d2cc6 --- /dev/null +++ b/deploy/tarsAdminRegistry/util/stop.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +bin="/usr/local/app/tars/tarsAdminRegistry/bin/tarsAdminRegistry" + +PID=`ps -eopid,cmd | grep "$bin"| grep "tarsAdminRegistry" | grep -v "grep"|grep -v "sh" |awk '{print $1}'` + +echo $PID + +if [ "$PID" != "" ]; then + kill -9 $PID + echo "kill -9 $PID" + fi + diff --git a/deploy/tars_install.sh b/deploy/tars_install.sh new file mode 100644 index 00000000..ab4a5bed --- /dev/null +++ b/deploy/tars_install.sh @@ -0,0 +1,29 @@ + +if [ ! -d /usr/local/app/tars/app_log ]; then + mkdir -p /data/log/tars + mkdir -p /usr/local/app/tars + mkdir -p /data/tars/app_log + ln -s /data/tars/app_log /usr/local/app/tars/app_log +fi + +if [ ! -d /usr/local/app/tars/remote_app_log ]; then + mkdir -p /data/tars/remote_app_log + ln -s /data/tars/remote_app_log /usr/local/app/tars/remote_app_log +fi + +cd /usr/local/app/tars/ + +chmod +x tarsAdminRegistry/util/*.sh +chmod +x tarsconfig/util/*.sh +chmod +x tarsnode/util/*.sh +chmod +x tarspatch/util/*.sh +chmod +x tarsregistry/util/*.sh +chmod +x tarsregistry/util/*.sh + +tarsregistry/util/start.sh ; +tarsAdminRegistry/util/start.sh; +tarsnode/util/start.sh ; +tarsconfig/util/start.sh; +tarspatch/util/start.sh; + + diff --git a/deploy/tarsconfig/conf/tarsconfig.conf b/deploy/tarsconfig/conf/tarsconfig.conf new file mode 100644 index 00000000..ee631934 --- /dev/null +++ b/deploy/tarsconfig/conf/tarsconfig.conf @@ -0,0 +1,55 @@ + + + enableset=n + setdivision=NULL + + node=tars.tarsnode.ServerObj@tcp -h 192.168.2.131 -p 19386 -t 60000 + app=tars + server=tarsconfig + localip=192.168.2.131 + local=tcp -h 127.0.0.1 -p 10001 -t 3000 + basepath=/usr/local/app/tars/bin + datapath=/usr/local/app/tars/tarsconfig/data + logpath=/usr/local/app/tars/app_log + logsize=100000000 + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + deactivating-timeout=3000 + logLevel=DEBUG + + allow + endpoint=tcp -h 192.168.2.131 -p 10001 -t 60000 + handlegroup=tars.tarsconfig.ConfigObjAdapter + maxconns=10240 + protocol=tars + queuecap=10000 + queuetimeout=60000 + servant=tars.tarsconfig.ConfigObj + shmcap=0 + shmkey=0 + threads=10 + + + + locator=tars.tarsregistry.QueryObj@tcp -h registry.tars.com -p 17890 + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=3 + stat=tars.tarsstat.StatObj + property=tars.tarsproperty.PropertyObj + modulename=tars.tarsconfig + + + + charset=utf8 + dbhost=db.tars.com + dbname=db_tars + dbpass=tars2015 + dbport=3306 + dbuser=tars + + diff --git a/deploy/tarsconfig/util/execute.sh b/deploy/tarsconfig/util/execute.sh new file mode 100644 index 00000000..7e5a7c3e --- /dev/null +++ b/deploy/tarsconfig/util/execute.sh @@ -0,0 +1,14 @@ +#!/bin/sh +ulimit -a +bin="/usr/local/app/tars/tarsconfig/bin/tarsconfig" + +PID=`ps -eopid,cmd | grep "$bin"| grep "tarsconfig" | grep -v "grep" |awk '{print $1}'` + +echo $PID + +if [ "$PID" != "" ]; then + kill -9 $PID + echo "kill -9 $PID" +fi +ulimit -c unlimited +$bin --config=/usr/local/app/tars/tarsconfig/conf/tarsconfig.conf & diff --git a/deploy/tarsconfig/util/start.sh b/deploy/tarsconfig/util/start.sh new file mode 100644 index 00000000..814809d3 --- /dev/null +++ b/deploy/tarsconfig/util/start.sh @@ -0,0 +1,2 @@ +#!/bin/sh +sh /usr/local/app/tars/tarsconfig/util/execute.sh diff --git a/deploy/tarsconfig/util/stop.sh b/deploy/tarsconfig/util/stop.sh new file mode 100644 index 00000000..cc5a2165 --- /dev/null +++ b/deploy/tarsconfig/util/stop.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +bin="/usr/local/app/tars/tarsconfig/bin/tarsconfig" + +PID=`ps -eopid,cmd | grep "$bin"| grep "tarsconfig" | grep -v "grep"|grep -v "sh" |awk '{print $1}'` + +echo $PID + +if [ "$PID" != "" ]; then + kill -9 $PID + echo "kill -9 $PID" + fi + diff --git a/deploy/tarsnode/conf/tarsnode.conf b/deploy/tarsnode/conf/tarsnode.conf new file mode 100644 index 00000000..7bc79794 --- /dev/null +++ b/deploy/tarsnode/conf/tarsnode.conf @@ -0,0 +1,66 @@ + + + enableset=n + setdivision=NULL + + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + stat=tars.tarsstat.StatObj + property=tars.tarsproperty.PropertyObj + modulename=tars.tarsnode + locator=tars.tarsregistry.QueryObj@tcp -h registry.tars.com -p 17890 + sync-invoke-timeout=6000 + asyncthread=3 + + + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + deactivating-timeout=3000 + app=tars + server=tarsnode + localip=192.168.2.131 + local=tcp -h 127.0.0.1 -p 19385 -t 10000 + basepath=/usr/local/app/tars/tarsnode/data + datapath=/usr/local/app/tars/tarsnode/data + logpath=/usr/local/app/tars/app_log + logLevel=DEBUG + + endpoint=tcp -h 192.168.2.131 -p 19385 -t 60000 + allow + maxconns=1024 + threads=5 + queuecap=10000 + queuetimeout=4000 + servant=tars.tarsnode.NodeObj + + + endpoint=tcp -h 192.168.2.131 -p 19386 -t 60000 + allow + maxconns=1024 + threads=5 + queuecap=10000 + queuetimeout=4000 + servant=tars.tarsnode.ServerObj + + + + + registryObj=tars.tarsregistry.RegistryObj + + heartTimeout=60 + monitorInterval=2 + synStatInterval=300 + + + file=serversCache.dat + minBlock=500 + maxBlock=500 + factor=1 + size=10M + + + diff --git a/deploy/tarsnode/util/execute.sh b/deploy/tarsnode/util/execute.sh new file mode 100644 index 00000000..b177867f --- /dev/null +++ b/deploy/tarsnode/util/execute.sh @@ -0,0 +1,17 @@ +#!/bin/sh +export PATH=${PATH}:/usr/local/app/tars/bin:/usr/local/jdk/bin; +bin="/usr/local/app/tars/tarsnode/bin/tarsnode" + +PID=`ps -eopid,cmd | grep "$bin"| grep "tarsnode" | grep -v "grep"|grep -v "sh" |awk '{print $1}'` + +echo $PID + +if [ "$PID" != "" ]; then + kill -9 $PID + echo "kill -9 $PID" +fi + +ulimit -c 409600 +ulimit -a + +$bin --locator="tars.tarsregistry.QueryObj@tcp -h registry.tars.com -p 17890" --config=/usr/local/app/tars/tarsnode/conf/tarsnode.conf & diff --git a/deploy/tarsnode/util/monitor.sh b/deploy/tarsnode/util/monitor.sh new file mode 100644 index 00000000..7d87eecd --- /dev/null +++ b/deploy/tarsnode/util/monitor.sh @@ -0,0 +1,14 @@ +#!/bin/sh +cd /usr/local/app/tars/tarsnode/util + +bin="/usr/local/app/tars/tarsnode/bin/tarsnode" + +$bin --monitor --config=/usr/local/app/tars/tarsnode/conf/tarsnode.conf + +ex=$? + +if [ $ex -ne 0 ]; then +# echo "monitor:"$ex", restart tarsnode" + sh /usr/local/app/tars/tarsnode/util/start.sh +fi + diff --git a/deploy/tarsnode/util/start.sh b/deploy/tarsnode/util/start.sh new file mode 100644 index 00000000..b9c7c002 --- /dev/null +++ b/deploy/tarsnode/util/start.sh @@ -0,0 +1,3 @@ +#!/bin/sh +cd /usr/local/app/tars/tarsnode/util +sh execute.sh > start.tmp 2>&1 diff --git a/deploy/tarsnode/util/stop.sh b/deploy/tarsnode/util/stop.sh new file mode 100644 index 00000000..c3fb50ab --- /dev/null +++ b/deploy/tarsnode/util/stop.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +bin="/usr/local/app/tars/tarsnode/bin/tarsnode" + +PID=`ps -eopid,cmd | grep "$bin"| grep "tarsnode" | grep -v "grep" |awk '{print $1}'` + +echo $PID + +if [ "$PID" != "" ]; then + kill -9 $PID + echo "kill -9 $PID" +fi + + diff --git a/deploy/tarsnode_install.sh b/deploy/tarsnode_install.sh new file mode 100644 index 00000000..e9dbcd10 --- /dev/null +++ b/deploy/tarsnode_install.sh @@ -0,0 +1,21 @@ + +if [ ! -d /usr/local/app/tars/app_log ]; then + mkdir -p /data/log/tars + mkdir -p /usr/local/app/tars + mkdir -p /data/tars/app_log + ln -s /data/tars/app_log /usr/local/app/tars/app_log +fi + +if [ ! -d /usr/local/app/tars/remote_app_log ]; then + mkdir -p /data/tars/remote_app_log + ln -s /data/tars/remote_app_log /usr/local/app/tars/remote_app_log +fi + +cd /usr/local/app/tars/ + + +chmod +x tarsnode/util/*.sh + +./tarsnode/util/start.sh + + diff --git a/deploy/tarspatch/conf/rsync.conf b/deploy/tarspatch/conf/rsync.conf new file mode 100644 index 00000000..6ac14109 --- /dev/null +++ b/deploy/tarspatch/conf/rsync.conf @@ -0,0 +1,10 @@ +[webrelease] + path = /usr/local/app/patchs/TmpPatch + readonly=false +[webrelease_patch] + path = /usr/local/app/patchs/tars + readonly=false +[webrelease_bak] + path = /data/tars.upload/tars.upload + readonly=false + diff --git a/deploy/tarspatch/conf/tarspatch.conf b/deploy/tarspatch/conf/tarspatch.conf new file mode 100644 index 00000000..c8de4d87 --- /dev/null +++ b/deploy/tarspatch/conf/tarspatch.conf @@ -0,0 +1,48 @@ + + directory=/usr/local/app/patchs/tars + uploadDirectory=/usr/local/app/patchs/tars.upload + size=1M + + enableset=n + setdivision=NULL + + node=tars.tarsnode.ServerObj@tcp -h 192.168.2.131 -p 19386 -t 60000 + app=tars + server=tarspatch + localip=192.168.2.131 + local=tcp -h 127.0.0.1 -p 10000 -t 3000 + basepath=/usr/local/app/tars/bin + datapath=/usr/local/app/tars/tarspatch/data + logpath=/usr/local/app/tars/app_log + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + deactivating-timeout=3000 + logLevel=DEBUG + + allow + endpoint=tcp -h 192.168.2.131 -p 10000 -t 6000 + handlegroup=tars.tarspatch.PatchObjAdapter + maxconns=20000 + protocol=tars + queuecap=10000 + queuetimeout=60000 + servant=tars.tarspatch.PatchObj + threads=3 + + + + locator=tars.tarsregistry.QueryObj@tcp -h registry.tars.com -p 17890 + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=3 + stat=tars.tarsstat.StatObj + property=tars.tarsproperty.PropertyObj + modulename=tars.tarspatch + + + diff --git a/deploy/tarspatch/util/execute.sh b/deploy/tarspatch/util/execute.sh new file mode 100644 index 00000000..e95f07a0 --- /dev/null +++ b/deploy/tarspatch/util/execute.sh @@ -0,0 +1,14 @@ +#!/bin/sh +ulimit -a +bin="/usr/local/app/tars/tarspatch/bin/tarspatch" + +PID=`ps -eopid,cmd | grep "$bin"| grep "tarspatch" | grep -v "grep" |awk '{print $1}'` + +echo $PID + +if [ "$PID" != "" ]; then + kill -9 $PID + echo "kill -9 $PID" +fi +ulimit -c unlimited +$bin --config=/usr/local/app/tars/tarspatch/conf/tarspatch.conf & diff --git a/deploy/tarspatch/util/init.sh b/deploy/tarspatch/util/init.sh new file mode 100644 index 00000000..70e10c55 --- /dev/null +++ b/deploy/tarspatch/util/init.sh @@ -0,0 +1,33 @@ + +if [ ! -d /usr/local/app/patchs ]; then + mkdir -p /usr/local/app/patchs + mkdir -p /data/tars/patchs/tars + mkdir -p /data/tars/patchs/TmpPatch + mkdir -p /data/tars/patchs/tars.upload + ln -s /data/tars/patchs/tars /usr/local/app/patchs/tars + ln -s /data/tars/patchs/TmpPatch /usr/local/app/patchs/TmpPatch + ln -s /data/tars/patchs/tars.upload /usr/local/app/patchs/tars.upload +fi + +bin="rsync" + +PID=`ps -eopid,cmd | grep "$bin" | grep -v "grep" |awk '{print $1}'` + +echo $PID + +if [ "$PID" != "" ]; then + kill -9 $PID + echo "kill -9 $PID" +fi + +rsync --address=web.tars.com --daemon --config=/usr/local/app/tars/tarspatch/conf/rsync.conf & + +#mkdir -p /usr/local/app/patchs +#cd /usr/local/app/patchs +#mkdir -p /data/tars/patchs/tars +#mkdir -p /data/tars/patchs/TmpPatch +#mkdir -p /data/tars/patchs/tars.upload +#ln -s /data/tars/patchs/tars /usr/local/app/patchs/tars +#ln -s /data/tars/patchs/TmpPatch /usr/local/app/patchs/TmpPatch +#ln -s /data/tars/patchs/tars.upload /usr/local/app/patchs/tars.upload + diff --git a/deploy/tarspatch/util/start.sh b/deploy/tarspatch/util/start.sh new file mode 100644 index 00000000..e5a9adeb --- /dev/null +++ b/deploy/tarspatch/util/start.sh @@ -0,0 +1,2 @@ +#!/bin/sh +sh /usr/local/app/tars/tarspatch/util/execute.sh diff --git a/deploy/tarspatch/util/stop.sh b/deploy/tarspatch/util/stop.sh new file mode 100644 index 00000000..c975d2d6 --- /dev/null +++ b/deploy/tarspatch/util/stop.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +bin="/usr/local/app/tars/tarspatch/bin/tarspatch" + +PID=`ps -eopid,cmd | grep "$bin"| grep "tarspatch" | grep -v "grep"|grep -v "sh" |awk '{print $1}'` + +echo $PID + +if [ "$PID" != "" ]; then + kill -9 $PID + echo "kill -9 $PID" + fi + diff --git a/deploy/tarsregistry/conf/tarsregistry.conf b/deploy/tarsregistry/conf/tarsregistry.conf new file mode 100644 index 00000000..6b41c411 --- /dev/null +++ b/deploy/tarsregistry/conf/tarsregistry.conf @@ -0,0 +1,103 @@ + + + + locator = tars.tarsregistry.QueryObj@tcp -h registry.tars.com -p 17890 + sync-invoke-timeout=10000 + async-invoke-timeout=60000 + refresh-endpoint-interval = 60000 + stat = tars.tarsstat.StatObj + property = tars.tarsproperty.PropertyObj + report-interval = 60000 + asyncthread = 3 + modulename = tars.tarsregistry + timeout-queue-size = 100 + + + app = tars + server = tarsregistry + localip = 192.168.2.131 + basepath = /usr/local/app/tars/tarsregistry/data + datapath = /usr/local/app/tars/tarsregistry/data + logpath = /usr/local/app/tars/app_log + netthread= 2 + notify=tars.tarsnotify.NotifyObj + + endpoint = tcp -h 192.168.2.131 -p 17890 -t 10000 + allow = + maxconns = 10000 + threads = 5 + queuecap = 10000 + queuetimeout= 4000 + servant = tars.tarsregistry.QueryObj + + + endpoint = tcp -h 192.168.2.131 -p 17891 -t 30000 + allow = + maxconns = 2048 + threads = 5 + queuecap = 10000 + queuetimeout= 4000 + servant = tars.tarsregistry.RegistryObj + + + + + dbhost = db.tars.com + dbname = db_tars + dbuser = tars + dbpass = tars2015 + dbport = 3306 + charset = utf8 + dbflag = CLIENT_MULTI_STATEMENTS + + + #加载object间隔时间(s) + loadObjectsInterval = 30 + reigistryTimeout = 150 + #node心跳超时时间(s) + nodeTimeout = 250 + #轮询server状态的间隔时间(s) + queryInterval = 150 + + #第一阶段加载时间间隔,位是秒 + loadObjectsInterval1 = 13 + #第一阶段加载最近时间更新的记录,默认是60秒 + LeastChangedTime1 = 600 + + #第二阶段(全量)加载时间间隔,单位是秒 + loadObjectsInterval2 = 3601 + + #node心跳超时时间,单位是秒 + nodeTimeout = 250 + #主控心跳超时检测时间,单位是秒 + reigistryTimeout = 150 + + #服务状态监控时间,单位是秒 + queryInterval = 150 + #服务状态监控加载最近时间更新的记录,单位是秒 + querylesttime = 300 + #主控心跳关闭开关,默认允许心跳检测,要迁移的时候设置次项为N + # heartbeatoff=Y + + asyncthread = 6 + + + #patch对象 + patchServerObj = tars.tarspatch.PatchObj + #查询列表对象 + QueryObjName = tars.tarsregistry.QueryObj + #node调用的Registry对象 + RegistryObjName = tars.tarsregistry.RegistryObj + + + min_block = 50 + max_block = 200 + factor = 1.2 + FilePath = /usr/local/app/tars/tarsregistry/util/objectCache.dat + FileSize = 8M + + + #node默认模板名称 + defaultTemplate = tars.tarsnode + + diff --git a/deploy/tarsregistry/util/env.sh b/deploy/tarsregistry/util/env.sh new file mode 100644 index 00000000..24580d07 --- /dev/null +++ b/deploy/tarsregistry/util/env.sh @@ -0,0 +1,2 @@ +export PATH=$PATH:/usr/local/app/gperftool32/bin +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/app/gperftool32/lib/ diff --git a/deploy/tarsregistry/util/execute.sh b/deploy/tarsregistry/util/execute.sh new file mode 100644 index 00000000..f5c4f672 --- /dev/null +++ b/deploy/tarsregistry/util/execute.sh @@ -0,0 +1,21 @@ +#!/bin/sh +ulimit -a +export PATH=${PATH}:/usr/local/tars/bin; +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/app/gperftool/lib; +#export HEAPCHECK=strict +export HEAP_CHECK_DUMP_DIRECTORY=. +HEAP_PROFILE_MMAP=true +HEAP_PROFILE_MMAP_LOG=true +#export HEAPPROFILE=registry +bin="/usr/local/app/tars/tarsregistry/bin/tarsregistry" + +PID=`ps -eopid,cmd | grep "$bin"| grep "tarsregistry" | grep -v "grep" |awk '{print $1}'` + +echo $PID + +if [ "$PID" != "" ]; then + kill -9 $PID + echo "kill -9 $PID" +fi +ulimit -c unlimited +$bin --config=/usr/local/app/tars/tarsregistry/conf/tarsregistry.conf & diff --git a/deploy/tarsregistry/util/start.sh b/deploy/tarsregistry/util/start.sh new file mode 100644 index 00000000..dbb45d08 --- /dev/null +++ b/deploy/tarsregistry/util/start.sh @@ -0,0 +1,2 @@ +#!/bin/sh +sh /usr/local/app/tars/tarsregistry/util/execute.sh diff --git a/deploy/tarsregistry/util/stop.sh b/deploy/tarsregistry/util/stop.sh new file mode 100644 index 00000000..2ef733b1 --- /dev/null +++ b/deploy/tarsregistry/util/stop.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +bin="/usr/local/app/tars/tarsregistry/bin/tarsregistry" + +PID=`ps -eopid,cmd | grep "$bin"| grep "tarsregistry" | grep -v "grep"|grep -v "sh" |awk '{print $1}'` + +echo $PID + +if [ "$PID" != "" ]; then + kill -9 $PID + echo "kill -9 $PID" + fi + diff --git a/docs-en/tars_config.md b/docs-en/tars_config.md new file mode 100644 index 00000000..eb99990f --- /dev/null +++ b/docs-en/tars_config.md @@ -0,0 +1,121 @@ +# Table of Contents +> * [Service Configuration Principle] (#main-chapter-1) +> * [Business Configuration Example] (#main-chapter-2) + +# 1. Principle of service configuration + +## 1.1. Configuration Profile Data Structure + +The configuration file information of the business service based on the Tars framework is consists of three levels: application configuration, Set application configuration, service and node configuration. + +The application level is the highest level configuration file, which can be referenced under the same application (business); + +The Set application configuration inherits from the application-level configuration, that is, a Set application configuration must have a corresponding application-level configuration; + +Both the service and the node configuration can reference the application configuration information and the Set application configuration, and the node configuration inherits the content of the service configuration by default. + +Priority: Node Configuration > Service Configuration > Set Application Configuration > Application Configuration + +As shown below: + +![tars-config](../docs/images/tars_config_jiegoutu.png) + +The Tars framework maintains these configuration information through two data tables, t_config_files and t_config_references. + +The main information of the t_config_files table: the service configuration file name, the configuration file type, the service name of the configuration file, the set group to which the configuration file belongs, the node ip to which the configuration file belongs, and the index id value of the configuration file and the set group information of the service. + +As shown below: + +![tars-config](../docs/images/tars_config_table1.png) + +The main information of the t_config_references table: the index id of the configuration file and the configuration file index id referenced by the id. + +As shown below: + +![tars-config](../docs/images/tars_config_table2.png) + +Note: The reference configuration file referred to in this article all denotes the application configuration file or the corresponding Set configuration file. + +## 1.2. Principle of implementation + +According to the above configuration file content structure, the Tars framework provides API for obtaining application-level configuration information and service-level configuration information (including obtaining reference configuration information at the same time) from the configServer service. + +### 1.2.1. Obtain application level configuration + +Currently, the service obtains application-level configuration information by using the addAppConfig interface provided in the framework, which is responsible for pulling the corresponding application configuration file from the configServer service to the local directory. +``` +bool addAppConfig(const string &filename); +``` +First, the application level configuration information is obtained from the configServer, and determine whether the business service contain the set group information. If yes, acquire the configuration information in the corresponding set packet, and finally the configuration information is saved in the local file. + +Note that the set configuration has a higher priority than the application configuration does. + +The main logic is as follows: + +![tars-config](../docs/images/tars_config_appconfig.png) + +The result of pulling the application configuration is as follows: + +![tars-config](../docs/images/tars_config_appconfig_result.png) + +###1.2.2. Acquire service level configuration + +At present, the service obtains the service level configuration information by using the addConfig interface provided in the framework, which is responsible for pulling the corresponding service configuration file from the configServer service to the local directory. +``` +bool addConfig(const string &filename); +``` +Obtaining service level configuration information is mainly divided into three steps: + +1.First, Using service name, configuration file name, set group information, and configuration information level as retrieval conditions to obtain configuration information and index id whose configuration information level is "service level". + +2.Secondly, the relation of obtaining corresponding configuration information index id (reference_id) which is referenced by index id in (1) from data table (t_config_referencses) is as follows: + +![tars-config](../docs/images/tars_config_references.png) + +If there is reference information, the configuration information corresponding to the references_id in the data table t_config_files is retrieved, and the configuration file corresponding to the references_id is retrieved whether it contains "set level configuration information", and if so, the set level configuration information is acquired. + +3.Combine the configuration information obtained in 2 and 2 in order, 2 is the first and 1 is the second. + +4.Then, the service name, the configuration file name, the node ip of the service, and the configuration information level are used as search conditions, and the configuration information and the index id of the node level are obtained, and then steps 2 and 3 are repeated. + +5.The order of composition of the service level configuration information finally returned to the business service is: service level reference configuration information + service level configuration information + node level reference configuration information + node level configuration information. + +# 2. Business configuration example + +## 2.1. Application Configuration + +Select the corresponding application (service) in the service tree, and select the "Application Configuration" page on the management interface opened on the right to add configuration, edit configuration, and so on. As shown below: + +![tars-config](../docs/images/tars_config_app1.png) + +Add the application configuration Test.conf as shown below: + +![tars-config](../docs/images/tars_config_app2.png) + +## 2.2. Set configuration + +Select the corresponding Set group on the service tree, and select the “Set Configuration” page on the management interface opened on the right side to add configuration, edit configuration, etc., as shown below: + +![tars-config](../docs/images/tars_config_set1.png) + +Add the application configuration Test.conf as shown below: + +![tars-config](../docs/images/tars_config_set2.png) + +> * Note: The corresponding Set configuration can only be added if the corresponding application profile is added. + +## 2.3. Service Configuration + +In the service tree on the left, select the service which need to be maintained. Click the “Service Configuration” page in the management interface on the left to add, edit, and delete the service configuration. As shown below: + +![tars-config](../docs/images/tars_config_server1.png) + +Add the application configuration Test.conf as shown below: + +![tars-config](../docs/images/tars_config_server2.png) + +In the service configuration, you can refer to the configuration content of the upper level (that is, the content of the application configuration of the application (business) and the configuration content of the set) as shown below: + +![tars-config](../docs/images/tars_config_server3_ref1.png) + +![tars-config](../docs/images/tars_config_server3_ref2.png) diff --git a/docs-en/tars_server_monitor.md b/docs-en/tars_server_monitor.md new file mode 100644 index 00000000..db06c321 --- /dev/null +++ b/docs-en/tars_server_monitor.md @@ -0,0 +1,53 @@ +# Contents +> * Overview +> * Service monitoring principle + +# 1. Overview + +For all business services based on the Tars(C++), Tars Node can provide real-time monitoring. The general service exits abnormally, and the phenomenon of zombie is actively monitored by the Tars Node, which makes the service run more reliable. + +# 2. Service monitoring principle + +## 2.1. Overview of service monitoring principles + +The Tars Node service will open a monitoring thread to be responsible for timing (interval time can be configured) to poll and monitor of the running status of all services managed by the Tars Node, and to report the running status of the service to the master. If a service meets the relevant trigger conditions, Tars Node takes corresponding measures to manage the service, so that the running status of the service is in real time under the monitoring of Tars Node. + +The above monitoring thread mainly includes the following key features: + +1.The frequency(in seconds) of monitoring thread going to poll the service. + +2.Timeout period (in seconds) for business service heartbeat reporting. If the process of processing a service under a node is time consuming, the user can consider increasing this value. + +3.The frequency (in seconds) that the Tars Node reports the running status of the service to the master. + +4.Tars Node has two methods to report the running status of the service to the master: single report and batch report. The batch report mode is selected by default. If the Tars Node manages a large number of services, you can choose the batch method to improve efficiency. + +## 2.2. Service monitoring strategy + +The monitoring thread considers the judgment strategy of several important monitoring points in the process of monitoring the service. + +### 2.2.1. A strategy for judging that a service process does not exist + +At present, the method for detecting whether the service process exists by the Tars Node is to send a NULL signal to the process of the specified ID through the kill function of the Linux system to determine whether the process exists. + +### 2.2.2. A strategy for judging that service has heartbeat timeout + +The heartbeat timeout period of the service is configured in the Node. This configuration applies to the heartbeat timeout period of all services managed by the Tars Node. + +Each business service reports a heartbeat time to the Tars Node every 10 seconds. The Tars Node checks whether the heartbeat time of each business service has timed out under a certain monitoring frequency. + +Tars Node also checks if the heartbeat time of all BindAdapters in each business service times out. + +### 2.2.3. A strategy for judging that service is allowed to start + +Considering various fault conditions and disaster tolerance characteristics, Tars Node will only send a start command to the service that meets the start condition. + +The strategies involved here are: + +1.A business service whose current state is in a transition state does not allow restarting, that is, a service in a state of "Activating", "Deactivating", "Destroying", "Loading", "Patching", "BatchPatching", and the like. + +2.The business service may be stopped through the O&M interface, that is, the service is manually stopped. At this time, the "internal working status" of the service is set to false. In this case, the Tars Node monitoring thread is not allowed to start the service. + +3.Some services may indeed have systemic problems that prevent them from starting successfully. In order to prevent frequent restarts of these services, the Tars Node adopts a"service restart penalty time" strategy for these services: that is, each time the service is restarted, the number of restarts and the restart time will be recorded, and the maximum restart time is N times in X seconds. After N times, the service still cannot be restarted, and then try to restart the service at a frequency of Y seconds. + +The default value in the current framework is: within 60 seconds, the service is started up to 10 times. And after 10 times of startup failure, it is retried every 600 seconds. \ No newline at end of file diff --git a/docs-en/tars_template.md b/docs-en/tars_template.md new file mode 100644 index 00000000..29f8e324 --- /dev/null +++ b/docs-en/tars_template.md @@ -0,0 +1,642 @@ +# table of contents +> * [1 Introducation of template configuration] (#main-chapter-1) +> * [2 Template configuration] (#main-chapter-2) +>>* [2.1 tars.default template](#chapter-1) +>>* [2.2 tars.tarsconfig template] (#chapter-2) +>>* [2.3 tars.tarslog template] (#chapter-3) +>>* [2.4 tars.tarsnotify template] (#chapter-4) +>>* [2.5 tars.tarspatch template] (#chapter-5) +>>* [2.6 tars.tarsproperty template] (#chapter-6) +>>* [2.7 tars.tarsstat template] (#chapter-7) +>>* [2.8 tars.tarsquerystat template] (#chapter-8) +>>* [2.9 tars.tarsqueryproperty template] (#chapter-9) +>>* [2.10 tars.tarsjava.default template] (#chapter-10) + +# 1. Introducation of template configuration + +A template configuration file must be designed when each Tars service starts running. The template configuration of the service deployed in the Tars web management system is organized by node. You need to create a template file by yourself if it is not on the web management system. + +The template configuration file for the Tars framework is organized by the parent template, main template and private template template configuration. + +The configuration file information of the parent template and main template is stored in the db_tars/t_profile_template data table. The table structure is as follows: + +![tars-template](../docs/images/tars_template_table1.png) + +The private template information is stored in the profile field of the db_tars/t_server_conf data table. +# 2. Template configuration + +Note that you need to modify the db.tars.com in the template to the machine that deploys the database. + +## 2.1. tars.default template + +Template name:tars.default(every service template inherit this template directly or indirectly) + +content: +```xml + + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + stat=tars.tarsstat.StatObj + property=tars.tarsproperty.PropertyObj + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + deactivating-timeout=3000 + logLevel=DEBUG + + + +``` + +## 2.2. tars.tarsconfig template + +Template name:tars.tarsconfig(inherit tars.default) + +content: +```xml + + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + deactivating-timeout=3000 + logLevel=DEBUG + + + + charset=utf8 + dbhost=db.tars.com + dbname=db_tars + dbpass=tars2015 + dbport=3306 + dbuser=tars + + +``` + +## 2.3. tars.tarslog template + +Template name:tars.tarslog(inherit tars.default) + +content: +```xml + + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + stat=tars.tarsstat.StatObj + property=tars.tarsproperty.PropertyObj + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=100000000 + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + deactivating-timeout=3000 + logLevel=ERROR + + + + logpath=/usr/local/app/tars/remote_app_log + logthread=10 + + hour=xx + + + + +``` +## 2.4. tars.tarsnotify template + +Template name:tars.tarsnotify(inherit tars.default) + +content: +```xml + + sql=CREATE TABLE `${TABLE}` ( `id` int(11) NOT NULL AUTO_INCREMENT, `application` varchar(128) DEFAULT '', `server_name` varchar(128) DEFAULT NULL, `container_name` varchar(128) DEFAULT '' , `node_name` varchar(128) NOT NULL DEFAULT '', `set_name` varchar(16) DEFAULT NULL, `set_area` varchar(16) DEFAULT NULL, `set_group` varchar(16) DEFAULT NULL, `server_id` varchar(100) DEFAULT NULL, `thread_id` varchar(20) DEFAULT NULL, `command` varchar(50) DEFAULT NULL, `result` text, `notifytime` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `index_name` (`server_name`), KEY `servernoticetime_i_1` (`notifytime`), KEY `indx_1_server_id` (`server_id`), KEY `query_index` (`application`,`server_name`,`node_name`,`set_name`,`set_area`,`set_group`) ) ENGINE\=InnoDB DEFAULT CHARSET\=utf8 + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + deactivating-timeout=3000 + logLevel=DEBUG + + + + charset=utf8 + dbhost=db.tars.com + dbpass=tars2015 + dbport=3306 + dbuser=tars + dbname=db_tars + + + min_block=50 + max_block=200 + factor=1.5 + file_path=./notify + file_size=50000000 + max_page_num=30 + max_page_size=20 + + + +``` +## 2.5. tars.tarspatch template + +Template name:tars.tarspatch(inherit tars.default) + +content: +```xml + + directory=/usr/local/app/patchs/tars + uploadDirectory=/usr/local/app/patchs/tars.upload + size=100M + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + deactivating-timeout=3000 + logLevel=DEBUG + + + +``` + +## 2.6. tars.tarsproperty template + +Template name:tars.tarsproperty(inherit tars.default) + +content: +```xml + + sql=CREATE TABLE `${TABLE}` (`stattime` timestamp NOT NULL default CURRENT_TIMESTAMP,`f_date` date NOT NULL default '1970-01-01', `f_tflag` varchar(8) NOT NULL default '',`master_name` varchar(128) NOT NULL default '',`master_ip` varchar(16) default NULL,`property_name` varchar(100) default NULL,`set_name` varchar(15) NOT NULL default '',`set_area` varchar(15) NOT NULL default '',`set_id` varchar(15) NOT NULL default '',`policy` varchar(20) default NULL,`value` varchar(255) default NULL, KEY (`f_date`,`f_tflag`,`master_name`,`master_ip`,`property_name`,`policy`),KEY `IDX_MASTER_NAME` (`master_name`),KEY `IDX_MASTER_IP` (`master_ip`),KEY `IDX_TIME` (`stattime`)) ENGINE\=Innodb + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + deactivating-timeout=3000 + logLevel=DEBUG + + + + charset + dbhost=db.tars.com + dbname=tars + dbport=3306 + dbuser=tars + dbpass=tars2015 + + + + dbhost=db.tars.com + dbname=tars_property + tbname=tars_property_ + dbuser=tars + dbpass=tars2015 + dbport=3306 + charset=utf8 + + + dbhost=db.tars.com + dbname=tars_property + tbname=tars_property_ + dbuser=tars + dbpass=tars2015 + dbport=3306 + charset=utf8 + + + + factor=1.5 + file=hashmap.txt + insertInterval=5 + maxBlock=200 + minBlock=100 + size=10M + + + Interval=10 + sql=insert ignore into t_master_property select master_name, property_name, policy from ${TABLE} group by master_name, property_name, policy; + + + +``` + +## 2.7. tars.tarsstat template + +Template name:tars.tarsstat(inherit tars.default) + +content: +```xml + + sql=CREATE TABLE `${TABLE}`( `stattime` timestamp NOT NULL default CURRENT_TIMESTAMP,`f_date` date NOT NULL default '1970-01-01', `f_tflag` varchar(8) NOT NULL default '',`source_id` varchar(15) default NULL,`master_name` varchar(64) default NULL,`slave_name` varchar(64) default NULL,`interface_name` varchar(64) default NULL,`tars_version` varchar(16) NOT NULL default '',`master_ip` varchar(15) default NULL,`slave_ip` varchar(21) default NULL,`slave_port` int(10) default NULL,`return_value` int(11) default NULL,`succ_count` int(10) unsigned default NULL,`timeout_count` int(10) unsigned default NULL,`exce_count` int(10) unsigned default NULL,`interv_count` varchar(128) default NULL,`total_time` bigint(20) unsigned default NULL,`ave_time` int(10) unsigned default NULL,`maxrsp_time` int(10) unsigned default NULL,`minrsp_time` int(10) unsigned default NULL,PRIMARY KEY (`source_id`,`f_date`,`f_tflag`,`master_name`,`slave_name`,`interface_name`,`master_ip`,`slave_ip`,`slave_port`,`return_value`,`tars_version`),KEY `IDX_TIME` (`stattime`),KEY `IDC_MASTER` (`master_name`),KEY `IDX_INTERFACENAME` (`interface_name`),KEY `IDX_FLAGSLAVE` (`f_tflag`,`slave_name`), KEY `IDX_SLAVEIP` (`slave_ip`),KEY `IDX_SLAVE` (`slave_name`),KEY `IDX_RETVALUE` (`return_value`),KEY `IDX_MASTER_IP` (`master_ip`),KEY `IDX_F_DATE` (`f_date`)) ENGINE\=MyISAM DEFAULT CHARSET\=utf8 + enWeighted=1 + useolddatabase=0 + time_out=600 + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + deactivating-timeout=3000 + logLevel=DEBUG + + + + tars.tarsstat;1.1.1.1 + + + masterfile=hashmap_master.txt + slavefile=hashmap_slave.txt + insertInterval=5 + enableStatCount=0 + size=8M + countsize=1M + + + interval=5 + insertDbThreadNum=4 + + + + dbhost=db.tars.com + dbname=tars_stat + tbname=tars_stat_ + dbuser=tars + dbpass=tars2015 + dbport=3306 + charset=utf8 + + + + +``` +## 2.8. tars.tarsquerystat template +Template name:tars.tarsquerystat(inherit tars.default) +``` + + + #whether to enable SET grouping + enableset=${enableset} + #full name of the SET group.(mtt.s.1) + setdivision=${setdivision} + + #address + locator =${locator} + #synchronous call timeout, default 3s(milliseconds) + sync-invoke-timeout = 3000 + #asynchronous call timeout, default 5s(milliseconds) + async-invoke-timeout =5000 + #the interval time to reacquire service list(milliseconds) + refresh-endpoint-interval = 60000 + #call service between modules [optional] + stat = tars.tarsstat.StatObj + #the service of attribute escalation [optional] + property = tars.tarsproperty.PropertyObj + #the interval time to report, default 60s(milliseconds) + report-interval = 60000 + #stat sampling ratio 1:n. For example, the sampling ratio is one thousandth when the sample-rate equal 1000 + sample-rate = 100000 + #the maximum number of samples in 1 minute + max-sample-count = 50 + + #the thread number of network asynchronous callback + asyncthread = ${asyncthread} + #template name + modulename = ${modulename} + + + #define all bound IPs + + #application name + app = ${app} + #service name + server = ${server} + #local ip + localip = ${localip} + + #local management socket[optional] + local = ${local} + #service data directory, executable file, configuration file, etc. + basepath = ${basepath} + # + datapath = ${datapath} + #log path + logpath = ${logpath} + #log size + logsize = 10M + #number of logs + # lognum = 10 + #configuration center address[optional] + config = tars.tarsconfig.ConfigObj + #inofrmation centor address[optional] + notify = tars.tarsnotify.NotifyObj + #remote LogServer[optional] + log = tars.tarslog.LogObj + #waiting time when closing the service + deactivating-timeout = 3000 + #the default value of scroll log level + logLevel=DEBUG + + + + + dbhost=db.tars.com + dbname=tars_stat + tbname=tars_stat_ + dbuser=tars + dbpass=tars2015 + dbport=3306 + charset=utf8 + + + +> +``` + +## 2.9.tars.tarsqueryproperty template +Template name:tars.tarsqueryproperty(inherit tars.default) +``` + + + #whether to enable SET grouping + enableset=${enableset} + #full name of the SET group.(mtt.s.1) + setdivision=${setdivision} + + #address + locator =${locator} + #synchronous call timeout, default 3s(milliseconds) + sync-invoke-timeout = 3000 + #asynchronous call timeout, default 5s(milliseconds) + async-invoke-timeout =5000 + #the interval time to reacquire service list(milliseconds) + refresh-endpoint-interval = 60000 + #call service between modules [optional] + stat = tars.tarsstat.StatObj + #the service of attribute escalation [optional] + property = tars.tarsproperty.PropertyObj + #the interval time to report, default 60s(milliseconds) + report-interval = 60000 + #stat sampling ratio 1:n. For example, the sampling ratio is one thousandth when the sample-rate equal 1000 + sample-rate = 100000 + #the maximum number of samples in 1 minute + max-sample-count = 50 + + #the thread number of network asynchronous callback + asyncthread = ${asyncthread} + #template name + modulename = ${modulename} + + + #define all bound IPs + + #application name + app = ${app} + #service name + server = ${server} + #local ip + localip = ${localip} + + #local management socket[optional] + local = ${local} + #service data directory, executable file, configuration file, etc. + basepath = ${basepath} + # + datapath = ${datapath} + #log path + logpath = ${logpath} + #log size + logsize = 10M + #number of logs + # lognum = 10 + #configuration center address[optional] + config = tars.tarsconfig.ConfigObj + #inofrmation centor address[optional] + notify = tars.tarsnotify.NotifyObj + #remote LogServer[optional] + log = tars.tarslog.LogObj + #waiting time when closing the service + deactivating-timeout = 3000 + #the default value of scroll log level + logLevel=DEBUG + + + + + dbhost=10.121.108.158 + dbname=tars_property + tbname=tars_property_ + dbuser=tars + dbpass=tars2015 + dbport=3306 + charset=utf8 + + + +> +``` +## 2.10. tars.tarsjava.default template + +Template name:.tars.tarsjava.default(inherit tars.default, every service template of tarsjava inherit this template directly or indirectly) + +content: +```xml + + + enableset=${enableset} + setdivision=${setdivision} + + asyncthread=${asyncthread} + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + stat=tars.tarsstat.StatObj + property=tars.tarsproperty.PropertyObj + report-interval=60000 + modulename=${modulename} + sample-rate=1000000 + max-sample-count=10 + + + deactivating-timeout=2000 + openthreadcontext=0 + threadcontextnum=10000 + threadcontextstack=32768 + logLevel=DEBUG + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + loglevel=DEBUG + logsize=15M + log=tars.tarslog.LogObj + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + mainclass=com.qq.cloud.tars.server.startup.Main + classpath=${basepath}/conf:${basepath}/lib + jvmparams=-Dcom.sun.management.jmxremote.ssl\=false -Dcom.sun.management.jmxremote.authenticate\=false -Xms2000m -Xmx2000m -Xmn1000m -Xss1000k -XX:PermSize\=128M -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction\=60 -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps -XX:+CMSParallelRemarkEnabled -XX:+CMSScavengeBeforeRemark -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction\=0 -verbosegc -XX:+PrintGCDetails -XX:ErrorFile\=${logpath}/${app}/${server}/jvm_error.log + sessiontimeout=120000 + sessioncheckinterval=60000 + tcpnodelay=true + udpbuffersize=8192 + charsetname=UTF-8 + backupfiles=bak1;bak2;bak3;conf + + + + +``` diff --git a/docs/images/tars_config_app1.png b/docs/images/tars_config_app1.png new file mode 100644 index 00000000..1c7ffd33 Binary files /dev/null and b/docs/images/tars_config_app1.png differ diff --git a/docs/images/tars_config_app2.png b/docs/images/tars_config_app2.png new file mode 100644 index 00000000..f76ad376 Binary files /dev/null and b/docs/images/tars_config_app2.png differ diff --git a/docs/images/tars_config_appconfig.png b/docs/images/tars_config_appconfig.png new file mode 100644 index 00000000..d4e215f0 Binary files /dev/null and b/docs/images/tars_config_appconfig.png differ diff --git a/docs/images/tars_config_appconfig_result.png b/docs/images/tars_config_appconfig_result.png new file mode 100644 index 00000000..2566f718 Binary files /dev/null and b/docs/images/tars_config_appconfig_result.png differ diff --git a/docs/images/tars_config_jiegoutu.png b/docs/images/tars_config_jiegoutu.png new file mode 100644 index 00000000..c69f86b8 Binary files /dev/null and b/docs/images/tars_config_jiegoutu.png differ diff --git a/docs/images/tars_config_references.png b/docs/images/tars_config_references.png new file mode 100644 index 00000000..82f19b28 Binary files /dev/null and b/docs/images/tars_config_references.png differ diff --git a/docs/images/tars_config_server1.png b/docs/images/tars_config_server1.png new file mode 100644 index 00000000..3ac046d2 Binary files /dev/null and b/docs/images/tars_config_server1.png differ diff --git a/docs/images/tars_config_server2.png b/docs/images/tars_config_server2.png new file mode 100644 index 00000000..fb0c2607 Binary files /dev/null and b/docs/images/tars_config_server2.png differ diff --git a/docs/images/tars_config_server3_ref1.png b/docs/images/tars_config_server3_ref1.png new file mode 100644 index 00000000..66d444c3 Binary files /dev/null and b/docs/images/tars_config_server3_ref1.png differ diff --git a/docs/images/tars_config_server3_ref2.png b/docs/images/tars_config_server3_ref2.png new file mode 100644 index 00000000..392c0dec Binary files /dev/null and b/docs/images/tars_config_server3_ref2.png differ diff --git a/docs/images/tars_config_set1.png b/docs/images/tars_config_set1.png new file mode 100644 index 00000000..ba0330a9 Binary files /dev/null and b/docs/images/tars_config_set1.png differ diff --git a/docs/images/tars_config_set2.png b/docs/images/tars_config_set2.png new file mode 100644 index 00000000..1f193f8b Binary files /dev/null and b/docs/images/tars_config_set2.png differ diff --git a/docs/images/tars_config_table1.png b/docs/images/tars_config_table1.png new file mode 100644 index 00000000..9e718f68 Binary files /dev/null and b/docs/images/tars_config_table1.png differ diff --git a/docs/images/tars_config_table2.png b/docs/images/tars_config_table2.png new file mode 100644 index 00000000..2d0ef905 Binary files /dev/null and b/docs/images/tars_config_table2.png differ diff --git a/docs/images/tars_template_table1.png b/docs/images/tars_template_table1.png new file mode 100644 index 00000000..4d90e53b Binary files /dev/null and b/docs/images/tars_template_table1.png differ diff --git a/docs/tars_config.md b/docs/tars_config.md new file mode 100644 index 00000000..766c3634 --- /dev/null +++ b/docs/tars_config.md @@ -0,0 +1,121 @@ +# 目录 +> * [业务配置原理] (#main-chapter-1) +> * [业务配置示例] (#main-chapter-2) + +# 1. 业务配置原理 + +## 1.1. 配置文件数据结构 + +基于Tars框架的业务服务的配置文件信息分为三层级别,应用配置、Set应用配置、服务配置和节点配置。 + +应用级为最高一级的配置文件,在同一应用(业务)下都可以被引用; + +Set应用配置继承自应用级配置,即一个Set应用配置必须有相应的应用级配置; + +服务和节点配置都可以引用应用配置信息和Set应用配置,并且节点配置默认继承服务配置的内容。 + +优先级:节点配置 > 服务配置 > Set应用配置 > 应用配置 + +如下图所示: + +![tars-config](images/tars_config_jiegoutu.png) + +Tars框架通过两个数据表来维护这些配置信息,t_config_files和t_config_references。 + +t_config_files表的主要信息:服务配置文件名称、配置文件类型、配置文件所属服务名,配置文件所属set分组,配置文件所属节点ip以及配置文件的索引id值以及该服务所在set分组信息。 + +如下图所示: + +![tars-config](images/tars_config_table1.png) + +t_config_references表的主要信息:配置文件的索引id以及该id所引用的配置文件索引id。 + +如下图所示: + +![tars-config](images/tars_config_table2.png) + +注意:本文所指的引用配置文件都是指应用配置文件或者相应的Set配置文件。 + +## 1.2. 实现原理 + +根据上述配置文件内容结构,Tars框架提供了从configServer服务获取应用级配置信息和服务级配置信息(包括同时获取引用配置信息)的接口。 + +### 1.2.1. 获取应用级配置 + +目前业务服务获取应用级配置信息的方式是使用框架中提供的addAppConfig接口,该接口负责向configServer服务拉取相应的应用配置文件到本地目录。 +``` +bool addAppConfig(const string &filename); +``` +首先向configServer获取应用级配置信息,同时判断该业务服务是否有set分组信息,如果有则获取相应set分组内的配置信息,最后把配置信息保存到本地文件中。 + +注意set配置优先级高于应用配置。 + +主要逻辑如下图: + +![tars-config](images/tars_config_appconfig.png) + +拉取应用配置的结果图如下: + +![tars-config](images/tars_config_appconfig_result.png) + +###1.2.2. 获取服务级配置 + +目前业务获取服务级别的配置信息方式是使用框架中提供的addConfig接口实现,该接口负责向configServer服务拉取相应的服务配置文件到本地目录。 +``` +bool addConfig(const string &filename); +``` +获取服务级的配置信息主要分为三个步骤: + +1.首先以服务名、配置文件名、set分组信息和配置信息等级为检索条件,获取配置信息等级为“服务级别”的配置信息和索引id + +2.其次,通过(1)中索引id从数据表t_config_referencses获取该id所引用的配置信息索引id(references_id),索引id的具体对应关系如下图: + +![tars-config](images/tars_config_references.png) + +如果存在引用信息,则检索数据表t_config_files中references_id对应的配置信息,同时检索该references_id对应的配置文件是否有“Set级配置信息”,如果有则再获取该set级别配置信息。 + +3.按顺序合并2和2中获取的配置信息,2为先1其次。 + +4.再次以服务名、配置文件名、服务所属节点ip和配置信息等级为检索条件,获取配置信息等级为节点级别的配置信息和索引id,然后重复2和3步骤。 + +5.最终返回给业务服务的服务级配置信息的组成顺序是:服务级的引用配置信息+服务级配置信息+节点级引用配置信息+节点级配置信息。 + +# 2. 业务配置示例 + +## 2.1. 应用配置 + +在业务树上选择相应的应用(业务),在右边打开的管理界面选择“应用配置”一页,就可以进行添加配置、编辑配置等操作。如下图: + +![tars-config](images/tars_config_app1.png) + +添加应用配置Test.conf,如下图: + +![tars-config](images/tars_config_app2.png) + +## 2.2. Set配置 + +在业务树上选择相应的Set分组,在右边打开的管理界面选择“Set配置”一页,就可以进行添加配置、编辑配置等操作,如下图: + +![tars-config](images/tars_config_set1.png) + +添加应用配置Test.conf,如下图: + +![tars-config](images/tars_config_set2.png) + +> * 注意:只有添加了相应的应用配置文件,才能添加相应的Set配置。 + +## 2.3. 服务配置 + +在左边的业务树选择需要维护的业务服务,点击左边打开的管理界面中“服务配置”一页,就可以进行服务配置的的添加、编辑和删除等操作。如下图: + +![tars-config](images/tars_config_server1.png) + +添加应用配置Test.conf,如下图: + +![tars-config](images/tars_config_server2.png) + +在服务配置里就可以引用上一级的配置内容(即所属应用(业务)的应用配置的内容以及所属Set的配置内容)如下图: + +![tars-config](images/tars_config_server3_ref1.png) + +![tars-config](images/tars_config_server3_ref2.png) diff --git a/docs/tars_server_monitor.md b/docs/tars_server_monitor.md new file mode 100644 index 00000000..27fefabf --- /dev/null +++ b/docs/tars_server_monitor.md @@ -0,0 +1,53 @@ +# Ŀ¼ +> * +> * ԭ + +# 1. + +лTarsʵֵҵNodeԺܺýʵʱءһķ쳣˳󣬶NodeʹеĿɿԸߡ + +# 2. ԭ + +## 2.1. ԭ + +Nodeͨһ̣߳ʱʱãѯNodeз״̬ʱϱ״̬ijشȡӦĴʩʹ״̬ʵʱNodeļ¡ + +ü߳Ҫ¼ؼأ + +1.̵߳Ƶʣλ룩 + +2.ҵϱijʱʱ䣨λ룩ijڵµķҵ̱ȽϺʱԿֵ + +3.Nodeϱ״̬Ƶʣλ룩 + +4.Nodeϱ״̬ķʽַʽĬѡϱNodeµķȽ϶࣬ѡʽЧʡ + +## 2.2. ز + +߳ڶԷļعУ漰Ҫļصжϲԡ + +### 2.2.1. жϷ̲ڲ + +ĿǰǼǷڵķͨlinuxϵͳkillָidNULLźжϽǷڡ + +### 2.2.2. жϷʱ + +ʱʱNodeõģʱڸNodeµзʱʱޡ + +ÿҵÿ10ϱһʱNodeNodeһļƵ¼ÿҵʱǷѾʱ + +NodeÿҵadapterʱǷʱ + +### 2.2.3. жϷ + +ǵֹԼԣNodeֻķз + +õIJǣ + +1.ĵǰ״̬ڹ״̬IJڡActivatingDeactivatingDestroyingLoadingPatchingBatchPatching״̬ + +2.пܷͨάֹͣģΪֹͣ÷񣬴ʱġڲ״̬ᱻΪfalse£Node߳ȥ + +3.Щȷʵϵͳ⣬޷ɹΪ˷ֹƵȥЩNodeسˡͷʱ䡱IJԣÿᱻ¼ʱ㣬XNΣNκ󣬷ʧܣYƵȥ + +ĿǰеĬֵǣ6010Σﵽ10ʧܺ,ÿ600һΡ diff --git a/docs/tars_template.md b/docs/tars_template.md new file mode 100644 index 00000000..9adb2fb0 --- /dev/null +++ b/docs/tars_template.md @@ -0,0 +1,642 @@ +# 目录 +> * [1 模版配置介绍] (#main-chapter-1) +> * [2 模版配置] (#main-chapter-2) +>>* [2.1 tars.default 模板](#chapter-1) +>>* [2.2 tars.tarsconfig 模板] (#chapter-2) +>>* [2.3 tars.tarslog 模板] (#chapter-3) +>>* [2.4 tars.tarsnotify 模板] (#chapter-4) +>>* [2.5 tars.tarspatch 模版] (#chapter-5) +>>* [2.6 tars.tarsproperty 模版] (#chapter-6) +>>* [2.7 tars.tarsstat 模版] (#chapter-7) +>>* [2.8 tars.tarsquerystat 模版] (#chapter-8) +>>* [2.9 tars.tarsqueryproperty 模版] (#chapter-9) +>>* [2.10 tars.tarsjava.default 模版] (#chapter-10) + +# 1. 模版配置介绍 + +每个Tars服务启动运行时,必须指定一个模版配置文件,在Tars web管理系统中部署的服务的模版配置由node进行组织生成,若不是在web管理系统上,则需要自己创建一个模版文件。 + +框架的模版配置文件由父模版、主模版、私有模版配置来组织。 + +父模版和主模版的配置信息,存放在db_tars/t_profile_template数据表里,表结构如下: + +![tars-template](images/tars_template_table1.png) + +私有模版信息,存放在db_tars/t_server_conf数据表的profile字段里面。 +# 2. 模板配置 + +注意模版中有db.tars.com时,需要修改成部署数据库的机器ip + +## 2.1. tars.default 模板 + +模版名称:tars.default(所有服务的模版都直接或者间接继承这个模版) + +内容: +```xml + + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + stat=tars.tarsstat.StatObj + property=tars.tarsproperty.PropertyObj + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + deactivating-timeout=3000 + logLevel=DEBUG + + + +``` + +## 2.2. tars.tarsconfig模版 + +模版名称:tars.tarsconfig(继承tars.default) + +内容: +```xml + + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + deactivating-timeout=3000 + logLevel=DEBUG + + + + charset=utf8 + dbhost=db.tars.com + dbname=db_tars + dbpass=tars2015 + dbport=3306 + dbuser=tars + + +``` + +## 2.3. tars.tarslog模版 + +模版名称:tars.tarslog(继承tars.default) + +内容: +```xml + + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + stat=tars.tarsstat.StatObj + property=tars.tarsproperty.PropertyObj + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=100000000 + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + deactivating-timeout=3000 + logLevel=ERROR + + + + logpath=/usr/local/app/tars/remote_app_log + logthread=10 + + hour=xx + + + + +``` +## 2.4. tars.tarsnotify模版 + +模版名称:tars.tarsnotify(继承tars.default) + +内容: +```xml + + sql=CREATE TABLE `${TABLE}` ( `id` int(11) NOT NULL AUTO_INCREMENT, `application` varchar(128) DEFAULT '', `server_name` varchar(128) DEFAULT NULL, `container_name` varchar(128) DEFAULT '' , `node_name` varchar(128) NOT NULL DEFAULT '', `set_name` varchar(16) DEFAULT NULL, `set_area` varchar(16) DEFAULT NULL, `set_group` varchar(16) DEFAULT NULL, `server_id` varchar(100) DEFAULT NULL, `thread_id` varchar(20) DEFAULT NULL, `command` varchar(50) DEFAULT NULL, `result` text, `notifytime` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `index_name` (`server_name`), KEY `servernoticetime_i_1` (`notifytime`), KEY `indx_1_server_id` (`server_id`), KEY `query_index` (`application`,`server_name`,`node_name`,`set_name`,`set_area`,`set_group`) ) ENGINE\=InnoDB DEFAULT CHARSET\=utf8 + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + deactivating-timeout=3000 + logLevel=DEBUG + + + + charset=utf8 + dbhost=db.tars.com + dbpass=tars2015 + dbport=3306 + dbuser=tars + dbname=db_tars + + + min_block=50 + max_block=200 + factor=1.5 + file_path=./notify + file_size=50000000 + max_page_num=30 + max_page_size=20 + + + +``` +## 2.5. tars.tarspatch模版 + +模版名称:tars.tarspatch(继承tars.default) + +内容: +```xml + + directory=/usr/local/app/patchs/tars + uploadDirectory=/usr/local/app/patchs/tars.upload + size=100M + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + deactivating-timeout=3000 + logLevel=DEBUG + + + +``` + +## 2.6. tars.tarsproperty模版 + +模版名称:tars.tarsproperty(继承tars.default) + +内容: +```xml + + sql=CREATE TABLE `${TABLE}` (`stattime` timestamp NOT NULL default CURRENT_TIMESTAMP,`f_date` date NOT NULL default '1970-01-01', `f_tflag` varchar(8) NOT NULL default '',`master_name` varchar(128) NOT NULL default '',`master_ip` varchar(16) default NULL,`property_name` varchar(100) default NULL,`set_name` varchar(15) NOT NULL default '',`set_area` varchar(15) NOT NULL default '',`set_id` varchar(15) NOT NULL default '',`policy` varchar(20) default NULL,`value` varchar(255) default NULL, KEY (`f_date`,`f_tflag`,`master_name`,`master_ip`,`property_name`,`policy`),KEY `IDX_MASTER_NAME` (`master_name`),KEY `IDX_MASTER_IP` (`master_ip`),KEY `IDX_TIME` (`stattime`)) ENGINE\=Innodb + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + deactivating-timeout=3000 + logLevel=DEBUG + + + + charset + dbhost=db.tars.com + dbname=tars + dbport=3306 + dbuser=tars + dbpass=tars2015 + + + + dbhost=db.tars.com + dbname=tars_property + tbname=tars_property_ + dbuser=tars + dbpass=tars2015 + dbport=3306 + charset=utf8 + + + dbhost=db.tars.com + dbname=tars_property + tbname=tars_property_ + dbuser=tars + dbpass=tars2015 + dbport=3306 + charset=utf8 + + + + factor=1.5 + file=hashmap.txt + insertInterval=5 + maxBlock=200 + minBlock=100 + size=10M + + + Interval=10 + sql=insert ignore into t_master_property select master_name, property_name, policy from ${TABLE} group by master_name, property_name, policy; + + + +``` + +## 2.7. tars.tarsstat模版 + +模版名称:tars.tarsstat(继承tars.default) + +内容: +```xml + + sql=CREATE TABLE `${TABLE}`( `stattime` timestamp NOT NULL default CURRENT_TIMESTAMP,`f_date` date NOT NULL default '1970-01-01', `f_tflag` varchar(8) NOT NULL default '',`source_id` varchar(15) default NULL,`master_name` varchar(64) default NULL,`slave_name` varchar(64) default NULL,`interface_name` varchar(64) default NULL,`tars_version` varchar(16) NOT NULL default '',`master_ip` varchar(15) default NULL,`slave_ip` varchar(21) default NULL,`slave_port` int(10) default NULL,`return_value` int(11) default NULL,`succ_count` int(10) unsigned default NULL,`timeout_count` int(10) unsigned default NULL,`exce_count` int(10) unsigned default NULL,`interv_count` varchar(128) default NULL,`total_time` bigint(20) unsigned default NULL,`ave_time` int(10) unsigned default NULL,`maxrsp_time` int(10) unsigned default NULL,`minrsp_time` int(10) unsigned default NULL,PRIMARY KEY (`source_id`,`f_date`,`f_tflag`,`master_name`,`slave_name`,`interface_name`,`master_ip`,`slave_ip`,`slave_port`,`return_value`,`tars_version`),KEY `IDX_TIME` (`stattime`),KEY `IDC_MASTER` (`master_name`),KEY `IDX_INTERFACENAME` (`interface_name`),KEY `IDX_FLAGSLAVE` (`f_tflag`,`slave_name`), KEY `IDX_SLAVEIP` (`slave_ip`),KEY `IDX_SLAVE` (`slave_name`),KEY `IDX_RETVALUE` (`return_value`),KEY `IDX_MASTER_IP` (`master_ip`),KEY `IDX_F_DATE` (`f_date`)) ENGINE\=MyISAM DEFAULT CHARSET\=utf8 + enWeighted=1 + useolddatabase=0 + time_out=600 + + enableset=${enableset} + setdivision=${setdivision} + + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + report-interval=60000 + sample-rate=100000 + max-sample-count=50 + asyncthread=${asyncthread} + modulename=${modulename} + + + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + logsize=10M + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + deactivating-timeout=3000 + logLevel=DEBUG + + + + tars.tarsstat;1.1.1.1 + + + masterfile=hashmap_master.txt + slavefile=hashmap_slave.txt + insertInterval=5 + enableStatCount=0 + size=8M + countsize=1M + + + interval=5 + insertDbThreadNum=4 + + + + dbhost=db.tars.com + dbname=tars_stat + tbname=tars_stat_ + dbuser=tars + dbpass=tars2015 + dbport=3306 + charset=utf8 + + + + +``` +## 2.8. tars.tarsquerystat模版 +模版名称:tars.tarsquerystat(继承tars.default) +``` + + + #是否启用SET分组 + enableset=${enableset} + #SET分组的全名.(mtt.s.1) + setdivision=${setdivision} + + #地址 + locator =${locator} + #同步调用超时时间,缺省3s(毫秒) + sync-invoke-timeout = 3000 + #异步超时时间,缺省5s(毫秒) + async-invoke-timeout =5000 + #重新获取服务列表时间间隔(毫秒) + refresh-endpoint-interval = 60000 + #模块间调用服务[可选] + stat = tars.tarsstat.StatObj + #属性上报服务[可选] + property = tars.tarsproperty.PropertyObj + #上报间隔时间,默认60s(毫秒) + report-interval = 60000 + #stat采样比1:n 例如sample-rate为1000时 采样比为千分之一 + sample-rate = 100000 + #1分钟内stat最大采样条数 + max-sample-count = 50 + + #网络异步回调线程个数 + asyncthread = ${asyncthread} + #模块名称 + modulename = ${modulename} + + + #定义所有绑定的IP + + #应用名称 + app = ${app} + #服务名称 + server = ${server} + #本地ip + localip = ${localip} + + #本地管理套接字[可选] + local = ${local} + #服务的数据目录,可执行文件,配置文件等 + basepath = ${basepath} + # + datapath = ${datapath} + #日志路径 + logpath = ${logpath} + #日志大小 + logsize = 10M + #日志数量 + # lognum = 10 + #配置中心的地址[可选] + config = tars.tarsconfig.ConfigObj + #信息中心的地址[可选] + notify = tars.tarsnotify.NotifyObj + #远程LogServer[可选] + log = tars.tarslog.LogObj + #关闭服务时等待时间 + deactivating-timeout = 3000 + #滚动日志等级默认值 + logLevel=DEBUG + + + + + dbhost=db.tars.com + dbname=tars_stat + tbname=tars_stat_ + dbuser=tars + dbpass=tars2015 + dbport=3306 + charset=utf8 + + + +> +``` + +## 2.9.tars.tarsqueryproperty 模版 +模版名称:tars.tarsqueryproperty(继承tars.default) +``` + + + #是否启用SET分组 + enableset=${enableset} + #SET分组的全名.(mtt.s.1) + setdivision=${setdivision} + + #地址 + locator =${locator} + #同步调用超时时间,缺省3s(毫秒) + sync-invoke-timeout = 3000 + #异步超时时间,缺省5s(毫秒) + async-invoke-timeout =5000 + #重新获取服务列表时间间隔(毫秒) + refresh-endpoint-interval = 60000 + #模块间调用服务[可选] + stat = tars.tarsstat.StatObj + #属性上报服务[可选] + property = tars.tarsproperty.PropertyObj + #上报间隔时间,默认60s(毫秒) + report-interval = 60000 + #stat采样比1:n 例如sample-rate为1000时 采样比为千分之一 + sample-rate = 100000 + #1分钟内stat最大采样条数 + max-sample-count = 50 + + #网络异步回调线程个数 + asyncthread = ${asyncthread} + #模块名称 + modulename = ${modulename} + + + #定义所有绑定的IP + + #应用名称 + app = ${app} + #服务名称 + server = ${server} + #本地ip + localip = ${localip} + + #本地管理套接字[可选] + local = ${local} + #服务的数据目录,可执行文件,配置文件等 + basepath = ${basepath} + # + datapath = ${datapath} + #日志路径 + logpath = ${logpath} + #日志大小 + logsize = 10M + #日志数量 + # lognum = 10 + #配置中心的地址[可选] + config = tars.tarsconfig.ConfigObj + #信息中心的地址[可选] + notify = tars.tarsnotify.NotifyObj + #远程LogServer[可选] + log = tars.tarslog.LogObj + #关闭服务时等待时间 + deactivating-timeout = 3000 + #滚动日志等级默认值 + logLevel=DEBUG + + + + + dbhost=10.121.108.158 + dbname=tars_property + tbname=tars_property_ + dbuser=tars + dbpass=tars2015 + dbport=3306 + charset=utf8 + + + +> +``` +## 2.10. tars.tarsjava.default模版 + +模版名称:.tars.tarsjava.default(继承tars.default,所有tarsjava服务的模版都直接或者间接继承这个模版) + +内容: +```xml + + + enableset=${enableset} + setdivision=${setdivision} + + asyncthread=${asyncthread} + locator=${locator} + sync-invoke-timeout=3000 + async-invoke-timeout=5000 + refresh-endpoint-interval=60000 + stat=tars.tarsstat.StatObj + property=tars.tarsproperty.PropertyObj + report-interval=60000 + modulename=${modulename} + sample-rate=1000000 + max-sample-count=10 + + + deactivating-timeout=2000 + openthreadcontext=0 + threadcontextnum=10000 + threadcontextstack=32768 + logLevel=DEBUG + app=${app} + server=${server} + localip=${localip} + local=${local} + basepath=${basepath} + datapath=${datapath} + logpath=${logpath} + loglevel=DEBUG + logsize=15M + log=tars.tarslog.LogObj + config=tars.tarsconfig.ConfigObj + notify=tars.tarsnotify.NotifyObj + log=tars.tarslog.LogObj + mainclass=com.qq.cloud.tars.server.startup.Main + classpath=${basepath}/conf:${basepath}/lib + jvmparams=-Dcom.sun.management.jmxremote.ssl\=false -Dcom.sun.management.jmxremote.authenticate\=false -Xms2000m -Xmx2000m -Xmn1000m -Xss1000k -XX:PermSize\=128M -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction\=60 -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps -XX:+CMSParallelRemarkEnabled -XX:+CMSScavengeBeforeRemark -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction\=0 -verbosegc -XX:+PrintGCDetails -XX:ErrorFile\=${logpath}/${app}/${server}/jvm_error.log + sessiontimeout=120000 + sessioncheckinterval=60000 + tcpnodelay=true + udpbuffersize=8192 + charsetname=UTF-8 + backupfiles=bak1;bak2;bak3;conf + + + + +``` diff --git a/patchclient/CMakeLists.txt b/patchclient/CMakeLists.txt new file mode 100644 index 00000000..f030f999 --- /dev/null +++ b/patchclient/CMakeLists.txt @@ -0,0 +1,6 @@ + +complice_module("patchclient") + +add_library(patch tars_patch.cpp) + +add_dependencies(patch FRAMEWORK-JCE) diff --git a/patchclient/patchclient.cpp b/patchclient/patchclient.cpp new file mode 100644 index 00000000..6104f787 --- /dev/null +++ b/patchclient/patchclient.cpp @@ -0,0 +1,150 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "tars_patch.h" +#include "util/tc_option.h" +#include "servant/Application.h" + +#include + +using namespace tars; + +void usage(int argc, char *argv[]) +{ + cout << "Usage:" << argv[0] << " --server=[server] --remote=[server-dir] --local=[local] [--remove]" << endl; + cout << "server: PatchObj@tcp -h ip -p port -t timeout" << endl; + cout << "remote: directory or file sync from server" << endl; + cout << "local: directory sync to local" << endl; + cout << "remove: remove local dir data" << endl; + exit(0); +} + +class PatchClientInterface : public TarsPatchNotifyInterface +{ +public: + virtual void onDownload(const FileInfo &fi) + { + cout << "------------------------------------" << endl; + cout << "downloading [" << fi.path << "] [" << fi.size*1.0/1024 << "K]" << endl; + } + virtual void onDownloading(const FileInfo &fi, size_t pos, const string &dest) + { + cout << "downloading [" << fi.path << " ->] [" << dest << "] [" << pos*100/fi.size << "/100%]" << endl; + } + virtual void onDownloadOK(const FileInfo &fi, const string &dest) + { + cout << "download ok [" << fi.path << "] -> [" << dest << "]" << endl; + } + virtual void onListFile() + { + cout << "listing files" << endl; + } + virtual void onListFileOK(const vector &vf) + { + cout << "list ok total [" << vf.size() << "] files" << endl; + } + virtual void onRemoveLocalDirectory(const string &sDir) + { + cout << "------------------------------------" << endl; + cout << "remove local directory [" << sDir << "]" << endl; + } + virtual void onRemoveLocalDirectoryOK(const string &sDir) + { + cout << "remove local directory ok [" << sDir << "]"<< endl; + cout << "------------------------------------" << endl; + } + virtual void onSetExecutable(const FileInfo &fi) + { + cout << "executable [" << fi.path << "]" << endl; + } + virtual void onDownloadAllOK(const vector &vf, time_t timeBegin, time_t timeEnd) + { + cout << "------------------------------------" << endl; + cout << "download all files succ." << endl; + } + + virtual void onReportTime(const string & sFile, const time_t timeBegin, const time_t timeEnd) + { + cout << "------------------------------------" << endl; + cout << "download '" << sFile << "', begin:" << timeBegin << ", end:" << timeEnd << endl; + } +}; + +typedef TC_AutoPtr PatchClientInterfacePtr; + +int main(int argc, char *argv[]) +{ + + if(argc < 2) + { + usage(argc, argv); + } + + try + { + + TC_Option option; + option.decode(argc, argv); + + //远程目录的相对路径 + string server = option.getValue("server"); + if(server.empty()) + { + cout << "server must not be empty." << endl; + return 0; + } + + CommunicatorFactory::getInstance()->getCommunicator()->setProperty("sync-invoke-timeout", "60000"); + PatchPrx pPtr; + CommunicatorFactory::getInstance()->getCommunicator()->stringToProxy(server, pPtr); + + //远程目录的相对路径 + string remote_dir = option.getValue("remote"); + if(remote_dir.empty()) + { + cout << "remote_dir must not be empty." << endl; + return 0; + } + + //本地同步路径 + string local_dir = option.getValue("local"); + if(local_dir.empty()) + { + cout << "local_dir must not be empty." << endl; + return 0; + } + + //是否先清空本地目录 + bool bRemove = option.hasParam("remove"); + + cout << "connecting to patch server" << endl; + TarsPatch op; + op.init(pPtr, remote_dir, local_dir); + cout << "connect ok to patch server" << endl; + op.setRemove(bRemove); + + PatchClientInterfacePtr p = new PatchClientInterface(); + op.download(p); + } + catch(exception &ex) + { + cout << ex.what() << endl; + } + + return 0; +} + + diff --git a/patchclient/tars_patch.cpp b/patchclient/tars_patch.cpp new file mode 100644 index 00000000..eba44aad --- /dev/null +++ b/patchclient/tars_patch.cpp @@ -0,0 +1,291 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#include "util/tc_file.h" +#include "util/tc_option.h" +#include "util/tc_md5.h" +#include "servant/TarsLogger.h" +#include "tars_patch.h" + +#include + +namespace tars +{ +TarsPatch::TarsPatch() +: _remove(false) +{ +} + +void TarsPatch::checkLocalDir() +{ + if (!tars::TC_File::isFileExistEx(_localDir, S_IFDIR)) + { + throw TarsPatchException("local dir '" + _localDir + "' must be a directory"); + } +} + +void TarsPatch::init(const PatchPrx &patchPrx, const string &remote_dir, const string &local_dir, const bool bCheck) +{ + _patchPrx = patchPrx; + _remoteDir = remote_dir; + _localDir = local_dir; + + if (bCheck) + { + checkLocalDir(); + } +} + +void TarsPatch::setRemove(bool bRemove) +{ + _remove = bRemove; +} + +void TarsPatch::download(const TarsPatchNotifyInterfacePtr &pPtr) +{ + //记录下载本次服务的总的时间开始 + time_t timeBegin = TNOW; + + checkLocalDir(); + + if (_remove) + { + string tmp = TC_File::simplifyDirectory(_localDir);// + "/" + _remoteDir); + + if (pPtr) pPtr->onRemoveLocalDirectory(tmp); + + int ret = TC_File::removeFile(tmp, true); + if (ret != 0) + { + throw TarsPatchException("remove '" + tmp + "' error", errno); + } + + if (pPtr) + { + pPtr->onRemoveLocalDirectoryOK(tmp); + } + } + + if (pPtr) + { + pPtr->onListFile(); + } + + //获取同步列表 + vector vf; + int ret = -1; + + int nRetryTime = 0; + +RETRY: + try + { + ret = _patchPrx->listFileInfo(_remoteDir, vf); + + } + catch(TarsException& ex) + { + //最多重试三次 + if(nRetryTime < 3) + { + nRetryTime++; + goto RETRY; + } + TLOGERROR("TarsPatch::download load error|" << __FILE__ << "," << __LINE__ << "|ex:" << ex.what() << endl); + throw TarsPatchException(ex.what()); + } + + if (ret != 0 && ret != 1) + { + throw TarsPatchException("listFileInfo error"); + } + + if (pPtr) + { + pPtr->onListFileOK(vf); + } + + if (ret == 0) + { + //path是路径, 对每个文件下载 + for (size_t i = 0; i < vf.size(); i++) + { + download(true, vf[i], pPtr); + } + } + else if (ret == 1) + { + //path是文件 + download(false, vf[0], pPtr); + } + + time_t timeEnd = TNOW; + + if (pPtr) + { + pPtr->onDownloadAllOK(vf, timeBegin, timeEnd); + } +} + +void TarsPatch::download(bool bDir, const FileInfo &fi, const TarsPatchNotifyInterfacePtr &pPtr) +{ + if (pPtr) + { + pPtr->onDownload(fi); + } + + //获取本地文件目录 + string file_dir = _localDir; + + if (bDir) + { + file_dir = tars::TC_File::simplifyDirectory(_localDir + "/" + tars::TC_File::extractFilePath(fi.path)); + + if (!file_dir.empty()) + { + //创建本地目录 + if (!tars::TC_File::makeDirRecursive(file_dir)) + { + throw TarsPatchException("create directory '" + file_dir + "' failed!"); + } + } + else + { + file_dir = "."; + } + } + + //本地文件名 + string file = tars::TC_File::simplifyDirectory(file_dir + "/" + tars::TC_File::extractFileName(fi.path)); + + FILE *fp = fopen(file.c_str(), "wb"); + if (!fp) + { + throw TarsPatchException("fopen file '" + file + "' error", errno); + } + + + time_t timeBegin = TNOW; + try + { + //循环下载文件到本地 + vector v; + int pos = 0; + while (true) + { + v.clear(); + int ret; + + int nRetryTime = 0; + + RETRY: + try + { + if (bDir) + { + ret = _patchPrx->download(tars::TC_File::simplifyDirectory(_remoteDir + "/" + fi.path), pos, v); + } + else + { + ret = _patchPrx->download(tars::TC_File::simplifyDirectory(_remoteDir), pos, v); + } + } + catch(TarsException& ex) + { + //最多重试两次 + if(nRetryTime < 2) + { + nRetryTime++; + goto RETRY; + } + TLOGERROR("TarsPatch::download load error|" << __FILE__ << "," << __LINE__ << "|"<onDownloading(fi, pos, file); + } + else if (ret == 1) + { + TLOGERROR("TarsPatch::download load succ|" << __FILE__ << "," << __LINE__ << "|" << fi.path << "|" << fi.md5<< "|" << pos << endl); + break; + } + } + } + catch (...) + { + fclose(fp); + fp = NULL; + TLOGERROR("TarsPatch::download error|" << __FILE__ << "," << __LINE__ << "|" << fi.path << "|" << fi.md5 << endl); + throw; + } + + fclose(fp); + + if (fi.canExec) + { + int ret = tars::TC_File::setExecutable(file, true); + if (ret == 0) + { + if (pPtr) + { + pPtr->onSetExecutable(fi); + } + } + else + { + throw TarsPatchException("set file '" + file + "' executable error!"); + } + } + + //检查MD5值 + if (!fi.md5.empty()) + { + std::string smd5 = tars::TC_MD5::md5file(file); + if (smd5 != fi.md5) + { + TLOGERROR("TarsPatch::download " << __FILE__ << "," << __LINE__ << "|" << fi.path << "|" << fi.md5 << "|" << smd5 << endl); + throw TarsPatchException(fi.path + "'s md5 is not equal to the file in patch server!");; + } + } + + time_t timeEnd = TNOW; + if (pPtr) + { + pPtr->onReportTime(fi.path, timeBegin, timeEnd); + } + + if (pPtr) + { + pPtr->onDownloadOK(fi, file); + } +} + + +} + + diff --git a/patchclient/tars_patch.h b/patchclient/tars_patch.h new file mode 100644 index 00000000..e339782c --- /dev/null +++ b/patchclient/tars_patch.h @@ -0,0 +1,194 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef __TARS_PATCH_H_ +#define __TARS_PATCH_H_ + +#include "Patch.h" + +namespace tars +{ +///////////////////////////////////////////////////////////////////////////////////// +/** + * patch服务客户端库 + * 采用该库实现从patch服务同步文件到本地 + */ + +///////////////////////////////////////////////////////////////////////////////////// +/** + * 下载异常 + */ +struct TarsPatchException : public TC_Exception +{ + TarsPatchException(const string& buffer) + : TC_Exception(buffer) + { + } + + TarsPatchException(const string& buffer, int err) + : TC_Exception(buffer, err) + { + } + + ~TarsPatchException() throw() + { + } +}; + +/** + * 下载通知接口 + */ +class TarsPatchNotifyInterface : public TC_HandleBase +{ +public: + /** + * 删除本地目录 + * @param sDir + */ + virtual void onRemoveLocalDirectory(const string& sDir) = 0; + + /** + * 删除本地目录成功 + * @param sDir + */ + virtual void onRemoveLocalDirectoryOK(const string& sDir) = 0; + + /** + * 开始获取文件链表 + */ + virtual void onListFile() = 0; + + /** + * 获取文件链表成功 + * @param vf + */ + virtual void onListFileOK(const vector& vf) = 0; + + /** + * 开始下载 + * @param fi + */ + virtual void onDownload(const FileInfo& fi) = 0; + + /** + * 下载文件成功 + * @param fi + * @param pos + * @param dest, 保存本地路径 + */ + virtual void onDownloading(const FileInfo& fi, size_t pos, const string& dest) = 0; + + /** + * 下载文件成功 + * @param fi + * @param dest, 保存本地路径 + */ + virtual void onDownloadOK(const FileInfo& fi, const string& dest) = 0; + + /** + * 设置可执行 + * @param fi + */ + virtual void onSetExecutable(const FileInfo& fi) = 0; + + /** + * 所有文件列表文件下载成功 + * @param vf + */ + virtual void onDownloadAllOK(const vector& vf, time_t timeBegin, time_t timeEnd) = 0; + + /** + * 上报下载文件所有的时间 + * @param file, beginTime, endTime + */ + virtual void onReportTime(const string& sFile, const time_t timeBegin, const time_t timeEnd) = 0; +}; + +typedef TC_AutoPtr TarsPatchNotifyInterfacePtr; + +/** + * 下载操作类 + */ +class TarsPatch +{ +public: + + /** + * 构造函数 + */ + TarsPatch(); + + /** + * 初始化 + * @param _patchPrx, patch服务器地址 + * @param remote_dir, 远程同步目录, 不能有..符号 + * @param local_dir, 同步到本地的目录 + */ + void init(const PatchPrx& patchPrx, const string& remote_dir, const string& local_dir, const bool bCheck = true); + + /** + * 设置是否删除本地目录 + * @param bRemove + */ + void setRemove(bool bRemove); + + /** + * 下载, 失败抛出异常 + * + */ + void download(const TarsPatchNotifyInterfacePtr& pPtr); + +protected: + + /** + * 下载某一个文件 + * @param fi + */ + void download(bool bDir, const FileInfo& fi, const TarsPatchNotifyInterfacePtr& pPtr); + + /** + * 检查本地路径 + */ + void checkLocalDir(); + +protected: + + /** + * 远程地址 + */ + string _remoteDir; + + /** + * 本地地址 + */ + string _localDir; + + /** + * 是否删除本地同步目录 + */ + bool _remove; + + /** + * patch服务器 + */ + PatchPrx _patchPrx; +}; + +} + +#endif + + diff --git a/sql/db_tars.sql b/sql/db_tars.sql new file mode 100644 index 00000000..dd4862d7 --- /dev/null +++ b/sql/db_tars.sql @@ -0,0 +1,641 @@ +-- MySQL dump 10.13 Distrib 5.6.26, for Linux (x86_64) +-- +-- Host: localhost Database: db_tars +-- ------------------------------------------------------ +-- Server version 5.6.26-log + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `t_adapter_conf` +-- + +DROP TABLE IF EXISTS `t_adapter_conf`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_adapter_conf` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `application` varchar(50) DEFAULT '', + `server_name` varchar(128) DEFAULT '', + `node_name` varchar(50) DEFAULT '', + `adapter_name` varchar(100) DEFAULT '', + `registry_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `thread_num` int(11) DEFAULT '1', + `endpoint` varchar(128) DEFAULT '', + `max_connections` int(11) DEFAULT '1000', + `allow_ip` varchar(255) NOT NULL DEFAULT '', + `servant` varchar(128) DEFAULT '', + `queuecap` int(11) DEFAULT NULL, + `queuetimeout` int(11) DEFAULT NULL, + `posttime` datetime DEFAULT '0000-00-00 00:00:00', + `lastuser` varchar(30) DEFAULT NULL, + `protocol` varchar(64) DEFAULT 'tars', + `handlegroup` varchar(64) DEFAULT '', + PRIMARY KEY (`id`), + UNIQUE KEY `application` (`application`,`server_name`,`node_name`,`adapter_name`), + KEY `adapter_conf_endpoint_index` (`endpoint`), + KEY `index_regtime_1` (`registry_timestamp`) +) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_adapter_conf` +-- + +LOCK TABLES `t_adapter_conf` WRITE; +/*!40000 ALTER TABLE `t_adapter_conf` DISABLE KEYS */; +INSERT INTO `t_adapter_conf` VALUES (1,'tars','tarspatch','192.168.2.131','tars.tarspatch.PatchObjAdapter','2015-11-28 16:16:55',10,'tcp -h 192.168.2.131 -t 60000 -p 10000',200000,'','tars.tarspatch.PatchObj',10000,60000,'2015-11-28 11:16:55','admin','tars',''),(2,'tars','tarsconfig','192.168.2.131','tars.tarsconfig.ConfigObjAdapter','2015-11-28 16:16:26',10,'tcp -h 192.168.2.131 -t 60000 -p 10001',200000,'','tars.tarsconfig.ConfigObj',10000,60000,'2015-11-28 11:16:26','admin','tars',''),(21,'tars','tarsnotify','192.168.2.131','tars.tarsnotify.NotifyObjAdapter','2015-11-29 02:48:13',5,'tcp -h 192.168.2.131 -t 60000 -p 10002',200000,'','tars.tarsnotify.NotifyObj',10000,60000,'2015-11-28 21:48:13','admin','tars',''); +/*!40000 ALTER TABLE `t_adapter_conf` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_ats_cases` +-- + +DROP TABLE IF EXISTS `t_ats_cases`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_ats_cases` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `casename` varchar(20) DEFAULT NULL, + `retvalue` text, + `paramvalue` text, + `interfaceid` int(11) DEFAULT NULL, + `posttime` datetime DEFAULT NULL, + `lastuser` varchar(30) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_ats_cases` +-- + +LOCK TABLES `t_ats_cases` WRITE; +/*!40000 ALTER TABLE `t_ats_cases` DISABLE KEYS */; +/*!40000 ALTER TABLE `t_ats_cases` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_ats_interfaces` +-- + +DROP TABLE IF EXISTS `t_ats_interfaces`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_ats_interfaces` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `objname` varchar(150) DEFAULT NULL, + `funcname` varchar(150) DEFAULT NULL, + `retype` text, + `paramtype` text, + `outparamtype` text, + `interfaceid` int(11) DEFAULT NULL, + `postime` datetime DEFAULT NULL, + `lastuser` varchar(30) DEFAULT NULL, + `request_charset` varchar(16) NOT NULL, + `response_charset` varchar(16) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `objname` (`objname`,`funcname`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_ats_interfaces` +-- + +LOCK TABLES `t_ats_interfaces` WRITE; +/*!40000 ALTER TABLE `t_ats_interfaces` DISABLE KEYS */; +/*!40000 ALTER TABLE `t_ats_interfaces` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_config_files` +-- + +DROP TABLE IF EXISTS `t_config_files`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_config_files` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `server_name` varchar(128) DEFAULT '', + `set_name` varchar(16) NOT NULL DEFAULT '', + `set_area` varchar(16) NOT NULL DEFAULT '', + `set_group` varchar(16) NOT NULL DEFAULT '', + `host` varchar(20) NOT NULL DEFAULT '', + `filename` varchar(128) DEFAULT NULL, + `config` longtext, + `posttime` datetime DEFAULT NULL, + `lastuser` varchar(50) DEFAULT NULL, + `level` int(11) DEFAULT '2', + `config_flag` int(10) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `application` (`server_name`,`filename`,`host`,`level`,`set_name`,`set_area`,`set_group`) +) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_config_files` +-- + +LOCK TABLES `t_config_files` WRITE; +/*!40000 ALTER TABLE `t_config_files` DISABLE KEYS */; +/*!40000 ALTER TABLE `t_config_files` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_config_history_files` +-- + +DROP TABLE IF EXISTS `t_config_history_files`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_config_history_files` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `configid` int(11) DEFAULT NULL, + `reason` varchar(128) DEFAULT '', + `reason_select` varchar(20) NOT NULL DEFAULT '', + `content` longtext, + `posttime` datetime DEFAULT NULL, + `lastuser` varchar(50) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_config_history_files` +-- + +LOCK TABLES `t_config_history_files` WRITE; +/*!40000 ALTER TABLE `t_config_history_files` DISABLE KEYS */; +/*!40000 ALTER TABLE `t_config_history_files` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_config_references` +-- + +DROP TABLE IF EXISTS `t_config_references`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_config_references` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `config_id` int(11) DEFAULT NULL, + `reference_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `config_id` (`config_id`,`reference_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_config_references` +-- + +LOCK TABLES `t_config_references` WRITE; +/*!40000 ALTER TABLE `t_config_references` DISABLE KEYS */; +/*!40000 ALTER TABLE `t_config_references` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_group_priority` +-- + +DROP TABLE IF EXISTS `t_group_priority`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_group_priority` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(128) DEFAULT '', + `group_list` text, + `list_order` int(11) DEFAULT '0', + `station` varchar(128) NOT NULL DEFAULT '', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_group_priority` +-- + +LOCK TABLES `t_group_priority` WRITE; +/*!40000 ALTER TABLE `t_group_priority` DISABLE KEYS */; +/*!40000 ALTER TABLE `t_group_priority` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_machine_tars_info` +-- + +DROP TABLE IF EXISTS `t_machine_tars_info`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_machine_tars_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `application` varchar(100) NOT NULL DEFAULT '', + `server_name` varchar(100) NOT NULL DEFAULT '', + `app_server_name` varchar(50) NOT NULL DEFAULT '', + `node_name` varchar(50) NOT NULL DEFAULT '', + `location` varchar(255) NOT NULL DEFAULT '', + `machine_type` varchar(50) NOT NULL DEFAULT '', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `update_person` varchar(64) NOT NULL DEFAULT '', + PRIMARY KEY (`application`,`server_name`,`node_name`), + UNIQUE KEY `id` (`id`), + KEY `tmachine_i_2` (`node_name`,`server_name`) +) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_machine_tars_info` +-- + +LOCK TABLES `t_machine_tars_info` WRITE; +/*!40000 ALTER TABLE `t_machine_tars_info` DISABLE KEYS */; +/*INSERT INTO `t_machine_tars_info` VALUES (2,'tars','tarsconfig','tars.tarsconfig','192.168.2.131','','','2015-08-07 16:04:03','admin'),(3,'tars','tarsnotify','tars.tarsnotify','192.168.2.131','','','2015-08-09 02:13:54','admin'),(1,'tars','tarspatch','tars.tarspatch','192.168.2.131','','','2015-08-07 15:57:50','admin');*/ +/*!40000 ALTER TABLE `t_machine_tars_info` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_node_info` +-- + +DROP TABLE IF EXISTS `t_node_info`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_node_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `node_name` varchar(128) DEFAULT '', + `node_obj` varchar(128) DEFAULT '', + `endpoint_ip` varchar(16) DEFAULT '', + `endpoint_port` int(11) DEFAULT '0', + `data_dir` varchar(128) DEFAULT '', + `load_avg1` float DEFAULT '0', + `load_avg5` float DEFAULT '0', + `load_avg15` float DEFAULT '0', + `last_reg_time` datetime DEFAULT '1970-01-01 00:08:00', + `last_heartbeat` datetime DEFAULT '1970-01-01 00:08:00', + `setting_state` enum('active','inactive') DEFAULT 'inactive', + `present_state` enum('active','inactive') DEFAULT 'inactive', + `tars_version` varchar(128) NOT NULL DEFAULT '', + `template_name` varchar(128) NOT NULL DEFAULT '', + `modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `group_id` int(11) DEFAULT '-1', + PRIMARY KEY (`id`), + UNIQUE KEY `node_name` (`node_name`), + KEY `indx_node_info_1` (`last_heartbeat`) +) ENGINE=InnoDB AUTO_INCREMENT=68 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_node_info` +-- + +LOCK TABLES `t_node_info` WRITE; +/*!40000 ALTER TABLE `t_node_info` DISABLE KEYS */; +INSERT INTO `t_node_info` VALUES (67,'192.168.2.131','tars.tarsnode.NodeObj@tcp -h 192.168.2.131 -p 19385 -t 60000','192.168.2.131',19385,'/usr/local/app/tars/tarsnode/data',0,0.12,0.39,'2015-11-29 13:36:07','2015-11-29 22:15:46','active','active','1.0.1_B001','','2015-11-29 14:15:46',-1); +/*!40000 ALTER TABLE `t_node_info` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_profile_template` +-- + +DROP TABLE IF EXISTS `t_profile_template`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_profile_template` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `template_name` varchar(128) DEFAULT '', + `parents_name` varchar(128) DEFAULT '', + `profile` text NOT NULL, + `posttime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `lastuser` varchar(30) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `template_name` (`template_name`) +) ENGINE=InnoDB AUTO_INCREMENT=366 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_profile_template` +-- + +LOCK TABLES `t_profile_template` WRITE; +/*!40000 ALTER TABLE `t_profile_template` DISABLE KEYS */; +INSERT INTO `t_profile_template` VALUES (353,'tars.default','tars.default','\n \n #是否启用SET分组\n enableset=${enableset}\n #SET分组的全名.(mtt.s.1)\n setdivision=${setdivision}\n \n #地址\n locator =${locator}\n #同步调用超时时间,缺省3s(毫秒)\n sync-invoke-timeout = 3000\n #异步超时时间,缺省5s(毫秒)\n async-invoke-timeout =5000\n #重新获取服务列表时间间隔(毫秒)\n refresh-endpoint-interval = 60000\n #模块间调用服务[可选]\n stat = tars.tarsstat.StatObj\n #属性上报服务[可选]\n property = tars.tarsproperty.PropertyObj\n #上报间隔时间,默认60s(毫秒)\n report-interval = 60000\n #stat采样比1:n 例如sample-rate为1000时 采样比为千分之一\n sample-rate = 100000\n #1分钟内stat最大采样条数\n max-sample-count = 50\n\n #网络异步回调线程个数\n asyncthread = ${asyncthread}\n #模块名称\n modulename = ${modulename}\n \n \n #定义所有绑定的IP\n \n #应用名称\n app = ${app}\n #服务名称\n server = ${server}\n #本地ip\n localip = ${localip}\n\n #本地管理套接字[可选]\n local = ${local}\n #服务的数据目录,可执行文件,配置文件等\n basepath = ${basepath}\n #\n datapath = ${datapath}\n #日志路径\n logpath = ${logpath}\n #日志大小\n logsize = 10M\n #日志数量\n # lognum = 10\n #配置中心的地址[可选]\n config = tars.tarsconfig.ConfigObj\n #信息中心的地址[可选]\n notify = tars.tarsnotify.NotifyObj\n #远程LogServer[可选]\n log = tars.tarslog.LogObj\n #关闭服务时等待时间\n deactivating-timeout = 3000\n #滚动日志等级默认值\n logLevel=DEBUG\n \n \n ','2016-09-22 17:36:01','admin'),(354,'tars.tarspatch','tars.default','\n \n \n log = tars.tarslog.LogObj\n logLevel = DEBUG\n \n \n\n directory=/usr/local/app/patchs/tars\n uploadDirectory=/usr/local/app/patchs/tars.upload\n size=1M\n','2015-08-07 22:06:46','admin'),(355,'tars.tarsconfig','tars.default','\n \n \n log = tars.tarslog.LogObj\n logLevel = DEBUG\n \n \n \n charset=utf8\n dbhost=db.tars.com\n dbname=db_tars\n dbpass=tars2015\n dbport=3306\n dbuser=tars\n\n \n','2015-08-07 22:05:24','admin'),(356,'tars.tarsnotify','tars.default','\n \n \n log = tars.tarslog.LogObj\n logLevel = DEBUG\n \n \n\n \n min_block=50 \n max_block=200 \n factor=1.5 \n file_path=./notify \n file_size=50000000 \n max_page_num=30 \n max_page_size=20 \n \n \n charset=utf8\n dbhost=db.tars.com\n dbname=db_tars\n dbpass=tars2015\n dbport=3306\n dbuser=tars\n dbname=db_tars\n\n \n\n sql=CREATE TABLE `${TABLE}` ( `id` int(11) NOT NULL AUTO_INCREMENT, `application` varchar(128) DEFAULT \'\', `server_name` varchar(128) DEFAULT NULL, `container_name` varchar(128) DEFAULT \'\' , `node_name` varchar(128) NOT NULL DEFAULT \'\', `set_name` varchar(16) DEFAULT NULL, `set_area` varchar(16) DEFAULT NULL, `set_group` varchar(16) DEFAULT NULL, `server_id` varchar(100) DEFAULT NULL, `thread_id` varchar(20) DEFAULT NULL, `command` varchar(50) DEFAULT NULL, `result` text, `notifytime` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `index_name` (`server_name`), KEY `servernoticetime_i_1` (`notifytime`), KEY `indx_1_server_id` (`server_id`), KEY `query_index` (`application`,`server_name`,`node_name`,`set_name`,`set_area`,`set_group`) ) ENGINE\\=InnoDB DEFAULT CHARSET\\=utf8\n','2016-09-26 15:21:52','admin'),(359,'tars.tarsstat','tars.default','\n sql= CREATE TABLE `${TABLE}`( `stattime` timestamp NOT NULL default CURRENT_TIMESTAMP,`f_date` date NOT NULL default \'1970-01-01\', `f_tflag` varchar(8) NOT NULL default \'\',`source_id` varchar(15) NOT NULL default \'\',`master_name` varchar(128) NOT NULL default \'\',`slave_name` varchar(128) NOT NULL default \'\',`interface_name` varchar(128) NOT NULL default \'\',`tars_version` varchar(16) NOT NULL default \'\',`master_ip` varchar(15) NOT NULL default \'\',`slave_ip` varchar(21) NOT NULL default \'\',`slave_port` int(10) NOT NULL default 0,`return_value` int(11) NOT NULL default 0,`succ_count` int(10) unsigned default NULL,`timeout_count` int(10) unsigned default NULL,`exce_count` int(10) unsigned default NULL,`interv_count` varchar(128) default NULL,`total_time` bigint(20) unsigned default NULL,`ave_time` int(10) unsigned default NULL,`maxrsp_time` int(10) unsigned default NULL,`minrsp_time` int(10) unsigned default NULL,PRIMARY KEY (`source_id`,`f_date`,`f_tflag`,`master_name`,`slave_name`,`interface_name`,`master_ip`,`slave_ip`,`slave_port`,`return_value`,`tars_version`),KEY `IDX_TIME` (`stattime`),KEY `IDC_MASTER` (`master_name`),KEY `IDX_INTERFACENAME` (`interface_name`),KEY `IDX_FLAGSLAVE` (`f_tflag`,`slave_name`), KEY `IDX_SLAVEIP` (`slave_ip`),KEY `IDX_SLAVE` (`slave_name`),KEY `IDX_RETVALUE` (`return_value`),KEY `IDX_MASTER_IP` (`master_ip`),KEY `IDX_F_DATE` (`f_date`)) ENGINE\\=InnoDB DEFAULT CHARSET\\=utf8\n enWeighted=1\n \n \n tars.tarsstat;1.1.1.1\n \n \n masterfile=hashmap_master.txt\n slavefile=hashmap_slave.txt\n insertInterval=5\n enableStatCount=0\n size=8M\n countsize=1M\n \n \n interval=5\n insertDbThreadNum=4\n \n \n \n dbhost=db.tars.com\n dbname=tars_stat\n tbname=tars_stat_\n dbuser=tars\n dbpass=tars2015\n dbport=3306\n charset=utf8\n \n \n \n','2016-09-26 17:25:45','admin'),(365,'tars.tarsjava.default','tars.default','\n \n enableset=${enableset}\n setdivision=${setdivision}\n \n locator=${locator}\n sync-invoke-timeout=20000\n async-invoke-timeout=20000\n refresh-endpoint-interval=60000\n stat=tars.tarsstat.StatObj\n property=tars.tarsproperty.PropertyObj\n report-interval=60000\n modulename=${modulename}\n sample-rate=100000\n max-sample-count=50\n \n \n app=${app}\n server=${server}\n localip=${localip}\n local=${local}\n basepath=${basepath}\n datapath=${datapath}\n logpath=${logpath}\n loglevel=DEBUG\n logsize=15M\n log=tars.tarslog.LogObj\n config=tars.tarsconfig.ConfigObj\n notify=tars.tarsnotify.NotifyObj\n mainclass=com.qq.tars.server.startup.Main\n classpath=${basepath}/conf:${basepath}/WEB-INF/classes:${basepath}/WEB-INF/lib\n jvmparams=-Dcom.sun.management.jmxremote.ssl\\=false -Dcom.sun.management.jmxremote.authenticate\\=false -Xms2000m -Xmx2000m -Xmn1000m -Xss1000k -XX:PermSize\\=128M -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction\\=60 -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps -XX:+CMSParallelRemarkEnabled -XX:+CMSScavengeBeforeRemark -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction\\=0 -verbosegc -XX:+PrintGCDetails -XX:ErrorFile\\=${logpath}/${app}/${server}/jvm_error.log\n sessiontimeout=120000\n sessioncheckinterval=60000\n tcpnodelay=true\n udpbuffersize=8192\n charsetname=UTF-8\n backupfiles=conf\n \n \n','2016-10-13 17:22:07','admin'),(358,'tars.tarsnode','tars.default','\n \n enableset=n \n setdivision=NULL\n \n modulename=tars.tarsnode\n locator=${locator}\n #缺省3s(毫秒)\n sync-invoke-timeout = 6000\n asyncthread=3\n \n \n app=tars\n server=tarsnode\n localip=${localip}\n local = tcp -h 127.0.0.1 -p 19385 -t 10000\n basepath=/usr/local/app/tars/tarsnode/data\n datapath=/usr/local/app/tars/tarsnode/data\n logpath= /usr/local/app/tars/app_log\n logLevel=DEBUG\n #配置绑定端口\n \n #监听IP地址\n endpoint = tcp -h ${localip} -p 19385 -t 60000\n #允许的IP地址\n allow =\n #最大连接数\n maxconns = 1024\n #当前线程个数\n threads = 5\n #流量限制\n queuecap = 10000\n #队列超时时间\n queuetimeout= 4000\n #处理对象\n servant = tars.tarsnode.NodeObj\n \n\n \n #监听IP地址\n endpoint = tcp -h ${localip} -p 19386 -t 60000\n #允许的IP地址\n allow =\n #最大连接数\n maxconns = 1024\n #当前线程个数\n threads = 5\n #流量限制\n queuecap = 10000\n #队列超时时间\n queuetimeout= 4000\n #处理对象\n servant = tars.tarsnode.ServerObj\n \n \n \n\n \n registryObj = ${registryObj}\n \n #业务心跳超时时间(s) \n heartTimeout = 60\n \n #监控server状态间隔时间(s) \n monitorInterval = 2 \n \n #跟主控/本地cache同步服务状态间隔时间(s) \n synStatInterval = 300\n \n \n \n file =serversCache.dat\n minBlock =500\n maxBlock =500\n factor =1\n size =10M\n \n \n','2015-08-07 22:04:39','admin'),(360,'tars.tarsproperty','tars.default','\n sql=CREATE TABLE `${TABLE}` (`stattime` timestamp NOT NULL default CURRENT_TIMESTAMP,`f_date` date NOT NULL default \'1970-01-01\', `f_tflag` varchar(8) NOT NULL default \'\',`master_name` varchar(128) NOT NULL default \'\',`master_ip` varchar(16) default NULL,`property_name` varchar(100) default NULL,`set_name` varchar(15) NOT NULL default \'\',`set_area` varchar(15) NOT NULL default \'\',`set_id` varchar(15) NOT NULL default \'\',`policy` varchar(20) default NULL,`value` varchar(255) default NULL, KEY (`f_date`,`f_tflag`,`master_name`,`master_ip`,`property_name`,`policy`),KEY `IDX_MASTER_NAME` (`master_name`),KEY `IDX_MASTER_IP` (`master_ip`),KEY `IDX_TIME` (`stattime`)) ENGINE=Innodb\n\n \n charset\n dbhost=db.tars.com\n dbname=tars\n dbport=3306\n dbuser=tars\n dbpass=tars2015\n \n \n \n dbhost=db.tars.com\n dbname=tars_property\n tbname=tars_property_\n dbuser=tars\n dbpass=tars2015\n dbport=3306\n charset=utf8\n \n \n dbhost=db.tars.com\n dbname=tars_property\n tbname=tars_property_\n dbuser=tars\n dbpass=tars2015\n dbport=3306\n charset=utf8\n \n \n \n factor=1.5\n file=hashmap.txt\n insertInterval=5\n maxBlock=200\n minBlock=100\n size=10M\n \n \n Interval=10\n sql=insert ignore into t_master_property select master_name, property_name, policy from ${TABLE} group by master_name, property_name, policy;\n \n','2015-08-25 12:15:52','admin'),(362,'tars.tarslog','tars.default','\n \n \n logLevel=ERROR\n \n \n \n logpath=/usr/local/app/tars/remote_app_log\n logthread=10 \n \n hour=xx\n \n \n','2016-10-13 17:31:36','admin'),(366,'tars.tarsquerystat','tars.default','\n\n\n dbhost=db.tars.com\n dbname=tars_stat\n tbname=tars_stat_\n dbuser=tars\n dbpass=tars2015\n dbport=3306\n charset=utf8\n \n\n','2017-01-04 17:13:40',NULL),(367,'tars.tarsqueryproperty','tars.default','\n\n\n dbhost=db.tars.com\n dbname=tars_property\n tbname=tars_property_\n dbuser=tars\n dbpass=tars2015\n dbport=3306\n charset=utf8\n \n\n','2017-01-04 17:14:01',NULL),('368', 'tars.tarsphp.default', 'tars.default', '\r\n \r\n enableset=${enableset}\r\n setdivision=${setdivision}\r\n \r\n locator=${locator}\r\n sync-invoke-timeout=20000\r\n async-invoke-timeout=20000\r\n refresh-endpoint-interval=60000\r\n stat=tars.tarsstat.StatObj\r\n property=tars.tarsproperty.PropertyObj\r\n report-interval=60000\r\n modulename=${modulename}\r\n sample-rate=100000\r\n max-sample-count=50\r\n \r\n \r\n app=${app}\r\n server=${server}\r\n localip=${localip}\r\n local=${local}\r\n basepath=${basepath}\r\n datapath=${datapath}\r\n logpath=${logpath}\r\n loglevel=DEBUG\r\n logsize=15M\r\n log=tars.tarslog.LogObj\r\n config=tars.tarsconfig.ConfigObj\r\n notify=tars.tarsnotify.NotifyObj\r\n logLevel=DEBUG\r\n php=/usr/bin/php\r\n buffer_output_size=12582912\r\n open_tcp_nodelay=1\r\n open_eof_check=0\r\n open_eof_split=0\r\n task_worker_num=1\r\n dispatch_mode=2\r\n daemonize=1\r\n \r\n \r\n\r\n', '2018-05-18 10:41:36', 'dpp'),(369,'tars.springboot','tars.tarsjava.default','\n\n<\n packageFormat=jar\n mainclass=-jar ${basepath}/${app}.${server}.jar\n \n\n','2017-01-04 17:14:01',NULL); +/*!40000 ALTER TABLE `t_profile_template` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_registry_info` +-- + +DROP TABLE IF EXISTS `t_registry_info`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_registry_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `locator_id` varchar(128) NOT NULL DEFAULT '', + `servant` varchar(128) NOT NULL DEFAULT '', + `endpoint` varchar(128) NOT NULL DEFAULT '', + `last_heartbeat` datetime DEFAULT '1970-01-01 00:08:00', + `present_state` enum('active','inactive') DEFAULT 'inactive', + `tars_version` varchar(128) NOT NULL DEFAULT '', + `modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `enable_group` char(1) DEFAULT 'N', + PRIMARY KEY (`id`), + UNIQUE KEY `locator_id` (`locator_id`,`servant`) +) ENGINE=InnoDB AUTO_INCREMENT=456487 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_registry_info` +-- + +LOCK TABLES `t_registry_info` WRITE; +/*!40000 ALTER TABLE `t_registry_info` DISABLE KEYS */; +INSERT INTO `t_registry_info` VALUES (456484,'192.168.2.131:17890','tars.tarsregistry.QueryObj','tcp -h 192.168.2.131 -p 17890 -t 10000','2015-11-29 22:16:16','active','1.0.1','2015-11-29 14:16:16','N'),(456485,'192.168.2.131:17890','tars.tarsregistry.RegistryObj','tcp -h 192.168.2.131 -p 17891 -t 30000','2015-11-29 22:16:16','active','1.0.1','2015-11-29 14:16:16','N'),(456486,'192.168.2.131:12000','tars.tarsAdminRegistry.AdminRegObj','tcp -h 192.168.2.131 -p 12000 -t 60000','2015-11-29 22:16:21','active','4.1.0.0_B002','2015-11-29 14:16:21','N'); +/*!40000 ALTER TABLE `t_registry_info` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_server_conf` +-- + +DROP TABLE IF EXISTS `t_server_conf`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_server_conf` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `application` varchar(128) DEFAULT '', + `server_name` varchar(128) DEFAULT '', + `node_group` varchar(50) NOT NULL DEFAULT '', + `node_name` varchar(50) NOT NULL DEFAULT '', + `registry_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `base_path` varchar(128) DEFAULT '', + `exe_path` varchar(128) NOT NULL DEFAULT '', + `template_name` varchar(128) NOT NULL DEFAULT '', + `bak_flag` int(11) NOT NULL DEFAULT '0', + `setting_state` enum('active','inactive') NOT NULL DEFAULT 'inactive', + `present_state` enum('active','inactive','activating','deactivating','destroyed') NOT NULL DEFAULT 'inactive', + `process_id` int(11) NOT NULL DEFAULT '0', + `patch_version` varchar(128) NOT NULL DEFAULT '', + `patch_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `patch_user` varchar(128) NOT NULL DEFAULT '', + `tars_version` varchar(128) NOT NULL DEFAULT '', + `posttime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `lastuser` varchar(30) DEFAULT NULL, + `server_type` enum('tars_cpp','not_tars','tars_java', 'tars_nodejs','tars_php') NOT NULL DEFAULT 'tars_cpp', + `start_script_path` varchar(128) DEFAULT NULL, + `stop_script_path` varchar(128) DEFAULT NULL, + `monitor_script_path` varchar(128) DEFAULT NULL, + `enable_group` char(1) DEFAULT 'N', + `enable_set` char(1) NOT NULL DEFAULT 'N', + `set_name` varchar(16) DEFAULT NULL, + `set_area` varchar(16) DEFAULT NULL, + `set_group` varchar(64) DEFAULT NULL, + `ip_group_name` varchar(64) DEFAULT NULL, + `profile` text, + `config_center_port` int(11) NOT NULL DEFAULT '0', + `async_thread_num` int(11) DEFAULT '3', + `server_important_type` enum('0','1','2','3','4','5') DEFAULT '0', + `remote_log_reserve_time` varchar(32) NOT NULL DEFAULT '65', + `remote_log_compress_time` varchar(32) NOT NULL DEFAULT '2', + `remote_log_type` int(1) NOT NULL DEFAULT '0', + `grid_flag` varchar(16) NOT NULL DEFAULT 'NORMAL', + PRIMARY KEY (`id`), + UNIQUE KEY `application` (`application`,`server_name`,`node_name`), + KEY `node_name` (`node_name`), + KEY `index_i_3` (`setting_state`,`server_type`,`application`,`server_name`,`node_name`), + KEY `index_regtime` (`registry_timestamp`) +) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_server_conf` +-- + +LOCK TABLES `t_server_conf` WRITE; +/*!40000 ALTER TABLE `t_server_conf` DISABLE KEYS */; +INSERT INTO `t_server_conf` VALUES (1,'tars','tarspatch','','192.168.2.131','2015-11-29 11:08:09','','/usr/local/app/tars/tarspatch/bin/tarspatch','tars.tarspatch',0,'active','active',9855,'','0000-00-00 00:00:00','','1.0.1','2015-08-07 23:57:50','admin','tars_cpp','','','','N','N','','','','','',0,3,'0','65','2',0,'NORMAL'),(2,'tars','tarsconfig','','192.168.2.131','2015-11-29 11:13:02','','/usr/local/app/tars/tarsconfig/bin/tarsconfig','tars.tarsconfig',0,'active','active',9815,'','0000-00-00 00:00:00','','1.0.1','2015-08-08 10:49:37','admin','tars_cpp','','','','N','N','','','','','',0,3,'0','65','2',0,'NORMAL'),(20,'tars','tarsnotify','','192.168.2.131','2015-11-29 11:13:02','','','tars.tarsnotify',0,'active','active',9838,'47','2015-11-28 22:26:40','admin','1.0.1','2015-11-28 21:48:13','admin','tars_cpp','','','','N','N','','','','','',0,3,'0','65','2',0,'NORMAL'); +/*!40000 ALTER TABLE `t_server_conf` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_server_group_relation` +-- + +DROP TABLE IF EXISTS `t_server_group_relation`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_server_group_relation` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `application` varchar(90) NOT NULL DEFAULT '', + `server_group` varchar(50) DEFAULT '', + `server_name` varchar(50) DEFAULT '', + `create_time` datetime DEFAULT NULL, + `creator` varchar(30) DEFAULT '', + PRIMARY KEY (`id`), + KEY `f_unique` (`application`,`server_group`,`server_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_server_group_relation` +-- + +LOCK TABLES `t_server_group_relation` WRITE; +/*!40000 ALTER TABLE `t_server_group_relation` DISABLE KEYS */; +/*!40000 ALTER TABLE `t_server_group_relation` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_server_group_rule` +-- + +DROP TABLE IF EXISTS `t_server_group_rule`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_server_group_rule` ( + `group_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `ip_order` enum('allow_denny','denny_allow') NOT NULL DEFAULT 'denny_allow', + `allow_ip_rule` text, + `denny_ip_rule` text, + `lastuser` varchar(50) DEFAULT NULL, + `modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `group_name` varchar(128) DEFAULT '', + `group_name_cn` varchar(128) DEFAULT '', + PRIMARY KEY (`group_id`), + UNIQUE KEY `group_name_index` (`group_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_server_group_rule` +-- + +LOCK TABLES `t_server_group_rule` WRITE; +/*!40000 ALTER TABLE `t_server_group_rule` DISABLE KEYS */; +/*!40000 ALTER TABLE `t_server_group_rule` ENABLE KEYS */; +UNLOCK TABLES; + + +-- +-- Table structure for table `t_server_patchs` +-- + +DROP TABLE IF EXISTS `t_server_patchs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_server_patchs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `server` varchar(50) DEFAULT NULL, + `version` varchar(1000) DEFAULT '', + `tgz` text, + `update_text` varchar(255) DEFAULT NULL, + `reason_select` varchar(255) DEFAULT NULL, + `document_complate` varchar(30) DEFAULT NULL, + `is_server_group` tinyint(2) NOT NULL DEFAULT '0', + `publish` tinyint(3) DEFAULT NULL, + `publish_time` datetime DEFAULT NULL, + `publish_user` varchar(30) DEFAULT NULL, + `upload_time` datetime DEFAULT NULL, + `upload_user` varchar(30) DEFAULT NULL, + `posttime` datetime DEFAULT NULL, + `lastuser` varchar(30) DEFAULT NULL, + `is_release_version` enum('true','false') DEFAULT 'true', + `package_type` tinyint(4) DEFAULT '0', + `group_id` varchar(64) NOT NULL DEFAULT '', + `default_version` tinyint(4) DEFAULT '0', + `md5` varchar(40) DEFAULT NULL, + `svn_version` varchar(50) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `server_patchs_server_index` (`server`), + KEY `index_patchs_i1` (`server`), + KEY `index_i_2` (`tgz`(50)) +) ENGINE=InnoDB AUTO_INCREMENT=52 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_server_patchs` +-- + +LOCK TABLES `t_server_patchs` WRITE; +/*!40000 ALTER TABLE `t_server_patchs` DISABLE KEYS */; +/*!40000 ALTER TABLE `t_server_patchs` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_task` +-- + +DROP TABLE IF EXISTS `t_task`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_task` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `task_no` varchar(40) DEFAULT NULL, + `serial` tinyint(1) DEFAULT NULL, + `user_name` varchar(20) DEFAULT NULL, + `create_time` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `f_task` (`task_no`) +) ENGINE=InnoDB AUTO_INCREMENT=139 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_task` +-- + +LOCK TABLES `t_task` WRITE; +/*!40000 ALTER TABLE `t_task` DISABLE KEYS */; +/*!40000 ALTER TABLE `t_task` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_task_item` +-- + +DROP TABLE IF EXISTS `t_task_item`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_task_item` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `task_no` varchar(40) DEFAULT NULL, + `item_no` varchar(40) DEFAULT NULL, + `application` varchar(30) DEFAULT NULL, + `server_name` varchar(50) DEFAULT NULL, + `node_name` varchar(20) DEFAULT NULL, + `command` varchar(20) DEFAULT NULL, + `parameters` text, + `start_time` datetime DEFAULT NULL, + `end_time` datetime DEFAULT NULL, + `status` int(11) DEFAULT NULL, + `set_name` varchar(20) DEFAULT NULL, + `log` text, + PRIMARY KEY (`id`), + UNIQUE KEY `f_uniq` (`item_no`,`task_no`), + KEY `f_task_no` (`task_no`), + KEY `f_index` (`application`,`server_name`,`command`) +) ENGINE=InnoDB AUTO_INCREMENT=142 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_task_item` +-- + +LOCK TABLES `t_task_item` WRITE; +/*!40000 ALTER TABLE `t_task_item` DISABLE KEYS */; +/*!40000 ALTER TABLE `t_task_item` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `t_web_release_conf` +-- + +DROP TABLE IF EXISTS `t_web_release_conf`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_web_release_conf` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `server` varchar(100) NOT NULL DEFAULT '', + `path` varchar(200) NOT NULL DEFAULT '', + `server_dir` varchar(200) NOT NULL DEFAULT '', + `is_server_group` tinyint(2) NOT NULL DEFAULT '0', + `enable_batch` tinyint(2) NOT NULL DEFAULT '0', + `user` varchar(200) NOT NULL DEFAULT '*', + `posttime` datetime DEFAULT NULL, + `lastuser` varchar(60) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `server` (`server`,`is_server_group`), + KEY `web_release_conf_server_index` (`server`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `t_web_release_conf` +-- + +LOCK TABLES `t_web_release_conf` WRITE; +/*!40000 ALTER TABLE `t_web_release_conf` DISABLE KEYS */; +/*!40000 ALTER TABLE `t_web_release_conf` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2016-11-24 14:28:02 diff --git a/sql/dump-sql.sh b/sql/dump-sql.sh new file mode 100644 index 00000000..7978fe12 --- /dev/null +++ b/sql/dump-sql.sh @@ -0,0 +1,2 @@ +mysqldump -uroot -proot@appinside db_tars > db_tars.sql + diff --git a/sql/exec-sql.sh b/sql/exec-sql.sh new file mode 100644 index 00000000..543edddc --- /dev/null +++ b/sql/exec-sql.sh @@ -0,0 +1,6 @@ +mysql -uroot -proot@appinside -e "create database db_tars" +mysql -uroot -proot@appinside -e "create database tars_stat" +mysql -uroot -proot@appinside -e "create database tars_property" + +mysql -uroot -proot@appinside db_tars < db_tars.sql + diff --git a/tarscpp b/tarscpp new file mode 160000 index 00000000..711a5ed7 --- /dev/null +++ b/tarscpp @@ -0,0 +1 @@ +Subproject commit 711a5ed70c9c70c3cb29ec731d77a3753a489ce5 diff --git a/thirdparty/rapidjson b/thirdparty/rapidjson new file mode 160000 index 00000000..73063f50 --- /dev/null +++ b/thirdparty/rapidjson @@ -0,0 +1 @@ +Subproject commit 73063f5002612c6bf64fe24f851cd5cc0d83eef9