2025-03-12 14:54:22 +08:00

729 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "DbCheck.h"
#include "ui_DbCheck.h"
#include <QHostInfo>
#include "pub_logger_api/logger.h"
#include <QNetworkDatagram>
#include "DbCheckSync.h"
#include <QMessageBox>
#include <QCloseEvent>
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);
if(res != iotSuccess)
{
mLastErroStr = tr("获取域信息失败");
return false;
}
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);
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<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);
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);
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);
}