#include "DbCheck.h" #include "ui_DbCheck.h" #include #include "pub_logger_api/logger.h" #include #include "DbCheckSync.h" #include #include using namespace iot_public; using namespace iot_dbms; struct SInfo { char cHostName[32]; // 节点名,即机器名 uint32 nGroup; // 组号,用于区分不同的项目 int nMaxId; // dbop_list表最大id int nHoldTime; // 持有时间,单位秒 int nWeight; // 权重,作用在持有时间相同时 bool bIpAdd; // 本机是否已添加虚拟IP SInfo() { memset( cHostName, 0, 32 ); nGroup = 0; nMaxId = 0; nHoldTime = 0; nWeight = 0; bIpAdd = false; } }; DbCheckThread::DbCheckThread(QObject *parent): m_ptrSysInfo(Q_NULLPTR),m_pRecvUdp(NULL) { m_isEnableSync = false; initTsdbApi(); } DbCheckThread::~DbCheckThread() { stopKeepAliveUdp(); wait(); releaseTsdbApi(); } bool DbCheckThread::startKeepAliveUdp() { if(!m_pRecvUdp) m_pRecvUdp = new QUdpSocket( this ); bool bRet = m_pRecvUdp->bind(6034); if ( bRet == false ) { mLastErroStr = tr("UDP绑定失败,端口号【%1】").arg(6034); return false; } connect( m_pRecvUdp, SIGNAL(readyRead()), this, SLOT(slotReceiveNetKeepAlivedInfo()) ); return true; } void DbCheckThread::stopKeepAliveUdp() { if(m_pRecvUdp) { m_pRecvUdp->close(); delete m_pRecvUdp; m_pRecvUdp = NULL; } } QMap &DbCheckThread::getDbResult() { return m_mapDBInfo; } SModelInfo &DbCheckThread::getSModelInfo() { return mModelInfo; } bool DbCheckThread::isEnableSync() { return m_isEnableSync; } QString DbCheckThread::getLastErro() { return mLastErroStr; } void DbCheckThread::run() { qint64 starTime = QDateTime::currentDateTime().toTime_t(); mLastErroStr = ""; updateModelInfo(); if(QThread::isInterruptionRequested()) { mLastErroStr = "查询终止"; return; } if(!resetSysInfo()) { return; } if(QThread::isInterruptionRequested()) { mLastErroStr = "查询终止"; return; } if(!initDbInfoVec()) { return; } if(QThread::isInterruptionRequested()) { mLastErroStr = "查询终止"; return; } if(!checkDbInfoVec()) { return; } if(QThread::isInterruptionRequested()) { mLastErroStr = "查询终止"; return; } qint64 endTime = QDateTime::currentDateTime().toTime_t(); if(endTime-starTime <3000) { msleep(3000 - (endTime-starTime)); } else { msleep(100); } } bool DbCheckThread::resetSysInfo() { if(!createSysInfoInstance(m_ptrSysInfo)) { mLastErroStr = tr("创建系统信息访问库失败"); return false; } if(m_ptrSysInfo == NULL) { mLastErroStr = tr("创建系统信息访问库失败"); return false; } return true; } void DbCheckThread::updateModelInfo() { CDbApi readApi(DB_CONN_MODEL_READ); if(readApi.open()) { mModelInfo.modelReadStatus = 1; readApi.close(); }else { mModelInfo.modelReadStatus = -1; } CDbApi writeApi(DB_CONN_MODEL_WRITE); if(writeApi.open()) { mModelInfo.modelWriteStatus = 1; writeApi.close(); }else { mModelInfo.modelWriteStatus = -1; } CDbApi hisApi(DB_CONN_HIS_READ); if(hisApi.open()) { mModelInfo.hisReaderStatus = 1; hisApi.close(); }else { mModelInfo.hisReaderStatus = -1; } if(NULL!= getOneUseableConn(true)) { mModelInfo.tsdbStatus = 1; } else { mModelInfo.tsdbStatus = -1; } } bool DbCheckThread::initDbInfoVec() { { QMutexLocker locker(&m_mapDbInfoMx); m_mapDBInfo.clear(); } //查询 SDomainInfo domainInfo; int res = m_ptrSysInfo->getDomainInfoByNodeName( QHostInfo::localHostName().toStdString(), domainInfo); if(res != iotSuccess) { mLastErroStr = tr("获取域信息失败"); return false; } iot_public::SDatabaseInfo stFirstConnect; std::vector vecLocalDBInfo; std::vector vecRemoteDBInfo; res = m_ptrSysInfo->getDBInfoByDomainId(domainInfo.nId, stFirstConnect, vecLocalDBInfo, vecRemoteDBInfo); if(res != iotSuccess) { mLastErroStr = tr("获取数据库信息失败"); return false; } QMutexLocker locker(&m_mapDbInfoMx); SDbItemInfo firstInfo; firstInfo.connect = stFirstConnect; firstInfo.sNodeName = QString::fromStdString(stFirstConnect.strNodeName); SNodeInfo nodeInfo; res = m_ptrSysInfo->getNodeInfoByName(stFirstConnect.strNodeName,nodeInfo); if(res == iotSuccess) { if(nodeInfo.eNodeType == ENodeType_VirtualNode) { m_isEnableSync = true; firstInfo.keepAliveStatus = 1; firstInfo.keepAliveTime = QDateTime::currentDateTime().toString("hh:mm:ss"); } } firstInfo.isFirst = true; m_mapDBInfo.insert(firstInfo.sNodeName,firstInfo); std::vector::iterator iter = vecLocalDBInfo.begin(); for(; iter!=vecLocalDBInfo.end(); ++iter) { if(iter->strNodeName == stFirstConnect.strNodeName) { continue; } SDbItemInfo info; SNodeInfo nodeInfo; info.connect = *iter; res = m_ptrSysInfo->getNodeInfoByName(iter->strNodeName,nodeInfo); if(res != iotSuccess) { continue; } //有虚拟节点则判断有启用同步 if(nodeInfo.eNodeType == ENodeType_VirtualNode) { m_isEnableSync = true; info.keepAliveStatus = 1; info.keepAliveTime = QDateTime::currentDateTime().toString("hh:mm:ss"); } info.isFirst = false; info.sNodeName = QString::fromStdString(iter->strNodeName); m_mapDBInfo.insert(info.sNodeName,info); } return true; } bool DbCheckThread::checkDbInfoVec() { bool bRet = true; QMap::iterator iter = m_mapDBInfo.begin(); for(; iter!=m_mapDBInfo.end(); ++iter) { if(QThread::isInterruptionRequested()) { mLastErroStr = "查询终止"; return false; } if(!checkDbInfo(iter.value())) { bRet = false; } } return bRet; } bool DbCheckThread::checkDbInfo(SDbItemInfo &info) { //获取首链接节点信息 SNodeInfo stNodeInfo; int res = m_ptrSysInfo->getNodeInfoByName(info.connect.strNodeName,stNodeInfo); if(res != iotSuccess) { mLastErroStr = tr("获取节点信息失败"); return false; } return check(info,stNodeInfo); } bool DbCheckThread::check(SDbItemInfo &stConnect, SNodeInfo &stNodeInfo) { if(!stNodeInfo.bIsUsed) { return true; } for(int index(1);index <= stNodeInfo.nNicNum;index++) { CDbPara para; if(index == 1) { para.setHostName(QString::fromStdString(stNodeInfo.strNic1Addr)); } if(index == 2) { para.setHostName(QString::fromStdString(stNodeInfo.strNic2Addr)); } QString firstColumn = QString("%1/%2").arg(QString::fromStdString(stNodeInfo.strName)).arg(para.getHostName()); stConnect.first = firstColumn; stConnect.isUsed = false; stConnect.maxSyncId = -1; stConnect.sNodeName = QString::fromStdString(stNodeInfo.strName); if(!DbCheck::getDbPara(stConnect.connect,para)) { mLastErroStr = tr("[%s]数据库类型错误!参数错误,直接默认为数据库状态不正常",firstColumn.toStdString().c_str()); continue; } CDbBaseApi baseApi(para); if(baseApi.open()) { stConnect.maxSyncId = DbCheckSync::getSyncMaxId(baseApi); stConnect.isUsed = true; baseApi.close(); }else { baseApi.close(); } } return true; } void DbCheckThread::slotReceiveNetKeepAlivedInfo() { QMutexLocker locker(&m_mapDbInfoMx); while ( m_pRecvUdp->hasPendingDatagrams() ) { QNetworkDatagram objDatagram = m_pRecvUdp->receiveDatagram(); QByteArray byMsg = objDatagram.data(); if ( byMsg.count() != sizeof(SInfo) ) { LOGERROR("接收的消息长度错误"); continue; } SInfo stTmp; memcpy( &stTmp, byMsg.data(), sizeof(SInfo) ); QMap::iterator iter = m_mapDBInfo.find(QString(stTmp.cHostName)); if(iter!=m_mapDBInfo.end()) { iter.value().keepAliveStatus = 1; iter.value().keepAliveTime =QDateTime::currentDateTime().toString("hh:mm:ss"); if(stTmp.bIpAdd) { iter.value().isDriftAddr = true; } } } } DbCheck::DbCheck(QWidget *parent) : QDialog(parent), ui(new Ui::DbCheck) { ui->setupUi(this); this->setWindowFlags(windowFlags()&~Qt::WindowContextHelpButtonHint); ui->tableWidget->setColumnWidth(0,220); ui->tableWidget->setColumnWidth(1,90); ui->tableWidget->setColumnWidth(2,90); ui->tableWidget->horizontalHeader()->setStretchLastSection(true); ui->tableWidget->setSelectionMode(QAbstractItemView::NoSelection); ui->tableWidget->setFocusPolicy(Qt::NoFocus); ui->pushButton->setFocusPolicy(Qt::NoFocus); connect(ui->pushButton,&QPushButton::clicked,this,&DbCheck::brush); connect( &m_checkThread, SIGNAL(finished()), this, SLOT(slotDbCheckFinished()) ); m_checkThread.startKeepAliveUdp(); brush(); } DbCheck::~DbCheck() { delete ui; } void DbCheck::brush() { if( m_checkThread.isRunning()) { ui->tip->setText(tr("正在刷新,无需再次提交刷新!")); return ; } m_checkThread.start(); ui->tip->setText(tr("正在刷新,请稍后!")); } void DbCheck::slotDbCheckFinished() { QString lastErro = m_checkThread.getLastErro(); if(lastErro.isEmpty()) { ui->tip->setText(tr("查询成功!")); updateModelInfo(); updateDbInfo(); updateDbSync(); updateDbKeepAlive(); } else { ui->tip->setText(tr("%1").arg(lastErro)); } } void DbCheck::updateModelInfo() { SModelInfo & modelInfo = m_checkThread.getSModelInfo(); updateModelInfo(modelInfo.modelReadStatus,ui->modelread); updateModelInfo(modelInfo.modelWriteStatus,ui->modelwrite); updateModelInfo(modelInfo.hisReaderStatus,ui->hisread); updateModelInfo(modelInfo.tsdbStatus,ui->label); } void DbCheck::updateDbInfo() { ui->tableWidget->setRowCount(0); //QMessageBox::warning(this,tr("提示"),tr("查询成功")); QMap & resultMap = m_checkThread.getDbResult(); QMap::iterator iter = resultMap.begin(); for(; iter!=resultMap.end(); ++iter) { SDbItemInfo& info = iter.value(); addTable(info); } } void DbCheck::updateDbSync() { QString isSyncStatus = tr("未知"); int syncId = -1; QString maxIdNode = tr("未知"); int isAbnormal = 0; int maxSyncId = -1; bool isSync = m_checkThread.isEnableSync(); QMap & resultMap = m_checkThread.getDbResult(); QMap::iterator iter = resultMap.begin(); for(; iter!=resultMap.end(); ++iter) { SDbItemInfo& info = iter.value(); if(iter == resultMap.begin()) { maxSyncId = info.maxSyncId; maxIdNode = info.sNodeName; isAbnormal = -1; isSyncStatus = tr("正常"); } else { if(maxSyncId > info.maxSyncId && info.maxSyncId != -1) { isSyncStatus = QString(tr("同步ID相差:%1")).arg(syncId-info.maxSyncId); isAbnormal = 1; } else if(maxSyncId < info.maxSyncId && info.maxSyncId != -1) { isSyncStatus = QString(tr("同步ID相差:%1")).arg(info.maxSyncId-syncId); maxSyncId = info.maxSyncId; maxIdNode = info.sNodeName; isAbnormal = 1; } if( info.maxSyncId == -1) { isAbnormal = 1; isSyncStatus = QString(tr("读取失败:%1")).arg(info.sNodeName); } } } if(!isSync) { ui->maxSyncID->setText(QString("%1(%2)").arg(maxIdNode).arg(maxSyncId)); ui->syncStatus->setText(tr("未启用")); } else { ui->maxSyncID->setText(QString("%1(%2)").arg(maxIdNode).arg(maxSyncId)); ui->syncStatus->setText(isSyncStatus); } if(isAbnormal == 1) { ui->maxSyncID->setStyleSheet("QLabel{color:red}"); ui->syncStatus->setStyleSheet("QLabel{color:red}"); } else if(isAbnormal == -1) { ui->maxSyncID->setStyleSheet("QLabel{color:green}"); ui->syncStatus->setStyleSheet("QLabel{color:green}"); } else { ui->maxSyncID->setStyleSheet("QLabel{color:black}"); ui->syncStatus->setStyleSheet("QLabel{color:black}"); } } void DbCheck::updateDbKeepAlive() { ui->virtualNode->setText(tr("无")); //ui->virtualNodeTime->setText(tr("未知")); ui->serverStatus->setText(tr("未知")); QMap & resultMap = m_checkThread.getDbResult(); QMap::iterator iter = resultMap.begin(); QString virtualNode = tr("无"); QString erroStr =""; bool isSync = m_checkThread.isEnableSync(); for(; iter!=resultMap.end(); ++iter) { SDbItemInfo& info = iter.value(); if(info.keepAliveStatus == 0) { erroStr = tr("服务未开启:%1").arg(info.sNodeName); } if(info.isDriftAddr) { virtualNode = info.sNodeName; } } if(!isSync) { ui->serverStatus->setText(tr("未启用")); ui->virtualNode->setText(tr("")); ui->virtualNode->setStyleSheet("QLabel{color:green}"); } else { if(!erroStr.isEmpty()) { ui->serverStatus->setText(erroStr); ui->serverStatus->setStyleSheet("QLabel{color:red}"); } else { ui->serverStatus->setText(tr("正常")); ui->serverStatus->setStyleSheet("QLabel{color:green}"); } // 2022-09-02 注释,经讨论只要IP漂移主机有值,就是绿色,否则就显示“” ui->virtualNode->setStyleSheet("QLabel{color:green}"); ui->virtualNode->setText(virtualNode); } } void DbCheck::updateModelInfo(int status, QLabel *lable) { if(status == 1) { lable->setText(tr("正常")); lable->setStyleSheet("QLabel{color:green}"); } else if(status == -1) { lable->setText(tr("异常")); lable->setStyleSheet("QLabel{color:red}"); } else { lable->setText(tr("未知")); lable->setStyleSheet("QLabel{color:black}"); } } void DbCheck::addTable(const SDbItemInfo &info) { int rowCount = ui->tableWidget->rowCount(); ui->tableWidget->setRowCount(rowCount+1); QTableWidgetItem *item = new QTableWidgetItem(); if(info.isFirst) { item->setData(Qt::DisplayRole,info.first+tr("(首链接)")); item->setTextAlignment(Qt::AlignCenter); ui->tableWidget->setItem(rowCount,0,item); }else { item->setData(Qt::DisplayRole,info.first); item->setTextAlignment(Qt::AlignCenter); ui->tableWidget->setItem(rowCount,0,item); } if(info.isUsed) { item = new QTableWidgetItem(); item->setTextColor(Qt::darkGreen); item->setData(Qt::DisplayRole,tr("正常")); item->setTextAlignment(Qt::AlignCenter); ui->tableWidget->setItem(rowCount,1,item); }else { item = new QTableWidgetItem(); item->setTextColor(Qt::red); item->setData(Qt::DisplayRole,tr("异常")); item->setTextAlignment(Qt::AlignCenter); ui->tableWidget->setItem(rowCount,1,item); } } bool DbCheck::getDbPara(SDatabaseInfo &stConnect, CDbPara ¶) { para.setDatabaseName(QString::fromStdString(stConnect.strServiceName)); LOGDEBUG("ServiceName:%s",stConnect.strServiceName.c_str()); para.setUserName(QString::fromStdString(stConnect.strUserName)); LOGDEBUG("UserName:%s",stConnect.strUserName.c_str()); para.setPassword(QString::fromStdString(stConnect.strUserPassword)); LOGDEBUG("Password:%s",stConnect.strUserPassword.c_str()); para.setPort(stConnect.nPort); LOGDEBUG("Port:%d",stConnect.nPort); switch (stConnect.eDBType) { case EDBType_ORACLE: para.setDbType(DB_ORACLE); LOGDEBUG("DBType:DB_ORACLE"); break; case EDBType_MYSQL: para.setDbType(DB_MYSQL); LOGDEBUG("DBType:DB_MYSQL"); break; case EDBType_OPENGAUSS: para.setDbType(DB_OPENGAUSS); LOGDEBUG("DBType:DB_OPENGAUSS"); break; case EDBType_KINGBASE: para.setDbType(DB_KINGBASE); LOGDEBUG("DBType:DB_KINGBASE"); break; default: LOGDEBUG("DBType:EDBType_Invalid"); return false; break; } return true; } void DbCheck::closeEvent(QCloseEvent *event) { if(m_checkThread.isRunning()) { QMessageBox::StandardButton btn = QMessageBox::question(this,"提示","正在查询,是否终止查询?"); if(btn == QMessageBox::Yes) { m_checkThread.requestInterruption(); } event->ignore(); return; } QDialog::closeEvent(event); }