File indexing completed on 2025-01-05 04:47:01
0001 /* 0002 * SPDX-FileCopyrightText: 2013 Daniel Vrátil <dvratil@redhat.com> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-or-later 0005 * 0006 */ 0007 0008 #include "storagedebugger.h" 0009 #include "storagedebuggeradaptor.h" 0010 0011 #include <QSqlError> 0012 #include <QSqlQuery> 0013 #include <QSqlRecord> 0014 0015 #include <QDBusConnection> 0016 0017 Akonadi::Server::StorageDebugger *Akonadi::Server::StorageDebugger::mSelf = nullptr; 0018 QMutex Akonadi::Server::StorageDebugger::mMutex; 0019 0020 using namespace Akonadi::Server; 0021 0022 Q_DECLARE_METATYPE(QList<QList<QVariant>>) 0023 Q_DECLARE_METATYPE(DbConnection) 0024 Q_DECLARE_METATYPE(QList<DbConnection>) 0025 0026 QDBusArgument &operator<<(QDBusArgument &arg, const DbConnection &con) 0027 { 0028 arg.beginStructure(); 0029 arg << con.id << con.name << con.start << con.trxName << con.transactionStart; 0030 arg.endStructure(); 0031 return arg; 0032 } 0033 0034 const QDBusArgument &operator>>(const QDBusArgument &arg, DbConnection &con) 0035 { 0036 arg.beginStructure(); 0037 arg >> con.id >> con.name >> con.start >> con.trxName >> con.transactionStart; 0038 arg.endStructure(); 0039 return arg; 0040 } 0041 0042 namespace 0043 { 0044 QList<DbConnection>::Iterator findConnection(QList<DbConnection> &vec, qint64 id) 0045 { 0046 return std::find_if(vec.begin(), vec.end(), [id](const DbConnection &con) { 0047 return con.id == id; 0048 }); 0049 } 0050 0051 } // namespace 0052 0053 StorageDebugger *StorageDebugger::instance() 0054 { 0055 mMutex.lock(); 0056 if (mSelf == nullptr) { 0057 mSelf = new StorageDebugger(); 0058 } 0059 mMutex.unlock(); 0060 0061 return mSelf; 0062 } 0063 0064 StorageDebugger::StorageDebugger() 0065 { 0066 qDBusRegisterMetaType<QList<QList<QVariant>>>(); 0067 qDBusRegisterMetaType<DbConnection>(); 0068 qDBusRegisterMetaType<QList<DbConnection>>(); 0069 new StorageDebuggerAdaptor(this); 0070 QDBusConnection::sessionBus().registerObject(QStringLiteral("/storageDebug"), this, QDBusConnection::ExportAdaptors); 0071 } 0072 0073 StorageDebugger::~StorageDebugger() = default; 0074 0075 void StorageDebugger::enableSQLDebugging(bool enable) 0076 { 0077 mEnabled = enable; 0078 } 0079 0080 void StorageDebugger::writeToFile(const QString &file) 0081 { 0082 mFile = std::make_unique<QFile>(file); 0083 mFile->open(QIODevice::WriteOnly); 0084 } 0085 0086 void StorageDebugger::addConnection(qint64 id, const QString &name) 0087 { 0088 QMutexLocker locker(&mMutex); 0089 const qint64 timestamp = QDateTime::currentMSecsSinceEpoch(); 0090 mConnections.push_back({id, name, timestamp, QString(), 0LL}); 0091 if (mEnabled) { 0092 Q_EMIT connectionOpened(id, timestamp, name); 0093 } 0094 } 0095 0096 void StorageDebugger::removeConnection(qint64 id) 0097 { 0098 QMutexLocker locker(&mMutex); 0099 auto con = findConnection(mConnections, id); 0100 if (con == mConnections.end()) { 0101 return; 0102 } 0103 mConnections.erase(con); 0104 0105 if (mEnabled) { 0106 Q_EMIT connectionClosed(id, QDateTime::currentMSecsSinceEpoch()); 0107 } 0108 } 0109 0110 void StorageDebugger::changeConnection(qint64 id, const QString &name) 0111 { 0112 QMutexLocker locker(&mMutex); 0113 auto con = findConnection(mConnections, id); 0114 if (con == mConnections.end()) { 0115 return; 0116 } 0117 con->name = name; 0118 0119 if (mEnabled) { 0120 Q_EMIT connectionChanged(id, name); 0121 } 0122 } 0123 0124 void StorageDebugger::addTransaction(qint64 connectionId, const QString &name, uint duration, const QString &error) 0125 { 0126 QMutexLocker locker(&mMutex); 0127 auto con = findConnection(mConnections, connectionId); 0128 if (con == mConnections.end()) { 0129 return; 0130 } 0131 con->trxName = name; 0132 con->transactionStart = QDateTime::currentMSecsSinceEpoch(); 0133 0134 if (mEnabled) { 0135 Q_EMIT transactionStarted(connectionId, name, con->transactionStart, duration, error); 0136 } 0137 } 0138 0139 void StorageDebugger::removeTransaction(qint64 connectionId, bool commit, uint duration, const QString &error) 0140 { 0141 QMutexLocker locker(&mMutex); 0142 auto con = findConnection(mConnections, connectionId); 0143 if (con == mConnections.end()) { 0144 return; 0145 } 0146 con->trxName.clear(); 0147 con->transactionStart = 0; 0148 0149 if (mEnabled) { 0150 Q_EMIT transactionFinished(connectionId, commit, QDateTime::currentMSecsSinceEpoch(), duration, error); 0151 } 0152 } 0153 0154 QList<DbConnection> StorageDebugger::connections() const 0155 { 0156 return mConnections; 0157 } 0158 0159 void StorageDebugger::queryExecuted(qint64 connectionId, const QSqlQuery &query, int duration) 0160 { 0161 if (!mEnabled) { 0162 return; 0163 } 0164 0165 const qint64 seq = ++mSequence; 0166 if (query.lastError().isValid()) { 0167 Q_EMIT queryExecuted(seq, 0168 connectionId, 0169 QDateTime::currentMSecsSinceEpoch(), 0170 duration, 0171 query.executedQuery(), 0172 query.boundValues(), 0173 0, 0174 QList<QList<QVariant>>(), 0175 query.lastError().text()); 0176 return; 0177 } 0178 0179 QSqlQuery q(query); 0180 QList<QVariantList> result; 0181 0182 if (q.first()) { 0183 const QSqlRecord record = q.record(); 0184 QVariantList row; 0185 const int numRecords = record.count(); 0186 row.reserve(numRecords); 0187 for (int i = 0; i < numRecords; ++i) { 0188 row << record.fieldName(i); 0189 } 0190 result << row; 0191 0192 int cnt = 0; 0193 do { 0194 const QSqlRecord record = q.record(); 0195 QVariantList row; 0196 const int numRecords = record.count(); 0197 row.reserve(numRecords); 0198 for (int i = 0; i < numRecords; ++i) { 0199 row << record.value(i); 0200 } 0201 result << row; 0202 } while (q.next() && ++cnt < 1000); 0203 } 0204 0205 const int querySize = query.isSelect() ? query.size() : query.numRowsAffected(); 0206 Q_EMIT queryExecuted(seq, 0207 connectionId, 0208 QDateTime::currentMSecsSinceEpoch(), 0209 duration, 0210 query.executedQuery(), 0211 query.boundValues(), 0212 querySize, 0213 result, 0214 QString()); 0215 0216 if (mFile && mFile->isOpen()) { 0217 QTextStream out(mFile.get()); 0218 out << query.executedQuery() << " " << duration << "ms\n"; 0219 } 0220 0221 // Reset the query 0222 q.seek(-1, false); 0223 } 0224 0225 #include "moc_storagedebugger.cpp"