729 lines
18 KiB
C++
Raw Normal View History

#include "DbCheck.h"
#include "ui_DbCheck.h"
#include <QHostInfo>
#include "pub_logger_api/logger.h"
#include <QNetworkDatagram>
#include "DbCheckSync.h"
#include <QMessageBox>
#include <QCloseEvent>
2025-03-12 14:17:53 +08:00
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<QString, SDbItemInfo> &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);
2025-03-12 14:54:22 +08:00
if(res != iotSuccess)
{
mLastErroStr = tr("获取域信息失败");
return false;
}
2025-03-12 14:17:53 +08:00
iot_public::SDatabaseInfo stFirstConnect;
std::vector<iot_public::SDatabaseInfo> vecLocalDBInfo;
std::vector<iot_public::SDatabaseInfo> vecRemoteDBInfo;
res = m_ptrSysInfo->getDBInfoByDomainId(domainInfo.nId,
stFirstConnect,
vecLocalDBInfo,
vecRemoteDBInfo);
2025-03-12 14:54:22 +08:00
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);
2025-03-12 14:54:22 +08:00
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);
2025-03-12 14:17:53 +08:00
std::vector<iot_public::SDatabaseInfo>::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);
2025-03-12 14:54:22 +08:00
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<QString,SDbItemInfo>::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);
2025-03-12 14:54:22 +08:00
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<QString,SDbItemInfo>::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<QString, SDbItemInfo> & resultMap = m_checkThread.getDbResult();
QMap<QString, SDbItemInfo>::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<QString, SDbItemInfo> & resultMap = m_checkThread.getDbResult();
QMap<QString, SDbItemInfo>::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<QString, SDbItemInfo> & resultMap = m_checkThread.getDbResult();
QMap<QString, SDbItemInfo>::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)
{
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);
}