Akonadi

storagedebugger.cpp
1 /*
2  * Copyright (C) 2013 Daniel Vrátil <[email protected]>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  */
19 
20 #include "storagedebugger.h"
21 #include "storagedebuggeradaptor.h"
22 
23 #include <QSqlQuery>
24 #include <QSqlRecord>
25 #include <QSqlError>
26 
27 #include <QDBusConnection>
28 
29 Akonadi::Server::StorageDebugger *Akonadi::Server::StorageDebugger::mSelf = nullptr;
30 QMutex Akonadi::Server::StorageDebugger::mMutex;
31 
32 using namespace Akonadi::Server;
33 
34 Q_DECLARE_METATYPE(QList< QList<QVariant> >)
35 Q_DECLARE_METATYPE(DbConnection)
36 Q_DECLARE_METATYPE(QVector<DbConnection>)
37 
38 QDBusArgument &operator<<(QDBusArgument &arg, const DbConnection &con)
39 {
40  arg.beginStructure();
41  arg << con.id
42  << con.name
43  << con.start
44  << con.trxName
45  << con.transactionStart;
46  arg.endStructure();
47  return arg;
48 }
49 
50 const QDBusArgument &operator>>(const QDBusArgument &arg, DbConnection &con)
51 {
52  arg.beginStructure();
53  arg >> con.id
54  >> con.name
55  >> con.start
56  >> con.trxName
57  >> con.transactionStart;
58  arg.endStructure();
59  return arg;
60 }
61 
62 namespace {
63 
65 {
66  return std::find_if(vec.begin(), vec.end(),
67  [id](const DbConnection &con) {
68  return con.id == id;
69  });
70 }
71 
72 }
73 
74 StorageDebugger *StorageDebugger::instance()
75 {
76  mMutex.lock();
77  if (mSelf == nullptr) {
78  mSelf = new StorageDebugger();
79  }
80  mMutex.unlock();
81 
82  return mSelf;
83 }
84 
85 StorageDebugger::StorageDebugger()
86 {
87  qDBusRegisterMetaType<QList< QList<QVariant> > >();
88  qDBusRegisterMetaType<DbConnection>();
89  qDBusRegisterMetaType<QVector<DbConnection>>();
90  new StorageDebuggerAdaptor(this);
91  QDBusConnection::sessionBus().registerObject(QStringLiteral("/storageDebug"),
92  this, QDBusConnection::ExportAdaptors);
93 }
94 
95 StorageDebugger::~StorageDebugger() = default;
96 
97 void StorageDebugger::enableSQLDebugging(bool enable)
98 {
99  mEnabled = enable;
100 }
101 
102 void StorageDebugger::writeToFile(const QString &file)
103 {
104  mFile.reset(new QFile(file));
105  mFile->open(QIODevice::WriteOnly);
106 }
107 
108 void StorageDebugger::addConnection(qint64 id, const QString &name)
109 {
110  QMutexLocker locker(&mMutex);
111  const qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
112  mConnections.push_back({ id, name, timestamp, QString(), 0ll });
113  if (mEnabled) {
114  Q_EMIT connectionOpened(id, timestamp, name);
115  }
116 }
117 
118 void StorageDebugger::removeConnection(qint64 id)
119 {
120  QMutexLocker locker(&mMutex);
121  auto con = findConnection(mConnections, id);
122  if (con == mConnections.end()) {
123  return;
124  }
125  mConnections.erase(con);
126 
127  if (mEnabled) {
128  Q_EMIT connectionClosed(id, QDateTime::currentMSecsSinceEpoch());
129  }
130 
131 }
132 
133 void StorageDebugger::changeConnection(qint64 id, const QString &name)
134 {
135  QMutexLocker locker(&mMutex);
136  auto con = findConnection(mConnections, id);
137  if (con == mConnections.end()) {
138  return;
139  }
140  con->name = name;
141 
142  if (mEnabled) {
143  Q_EMIT connectionChanged(id, name);
144  }
145 
146 }
147 
148 void StorageDebugger::addTransaction(qint64 connectionId, const QString &name,
149  uint duration, const QString &error)
150 {
151  QMutexLocker locker(&mMutex);
152  auto con = findConnection(mConnections, connectionId);
153  if (con == mConnections.end()) {
154  return;
155  }
156  con->trxName = name;
157  con->transactionStart = QDateTime::currentMSecsSinceEpoch();
158 
159  if (mEnabled) {
160  Q_EMIT transactionStarted(connectionId, name, con->transactionStart, duration, error);
161  }
162 
163 }
164 
165 void StorageDebugger::removeTransaction(qint64 connectionId, bool commit,
166  uint duration, const QString &error)
167 {
168 
169  QMutexLocker locker(&mMutex);
170  auto con = findConnection(mConnections, connectionId);
171  if (con == mConnections.end()) {
172  return;
173  }
174  con->trxName.clear();
175  con->transactionStart = 0;
176 
177  if (mEnabled) {
178  Q_EMIT transactionFinished(connectionId, commit, QDateTime::currentMSecsSinceEpoch(),
179  duration, error);
180  }
181 }
182 
183 QVector<DbConnection> StorageDebugger::connections() const
184 {
185  return mConnections;
186 }
187 
188 void StorageDebugger::queryExecuted(qint64 connectionId, const QSqlQuery &query, int duration)
189 {
190  if (!mEnabled) {
191  return;
192  }
193 
194  const qint64 seq = ++mSequence;
195  if (query.lastError().isValid()) {
196  Q_EMIT queryExecuted(seq, connectionId, QDateTime::currentMSecsSinceEpoch(),
197  duration, query.executedQuery(), query.boundValues(), 0,
198  QList<QList<QVariant>>(), query.lastError().text());
199  return;
200  }
201 
202  QSqlQuery q(query);
203  QList<QVariantList> result;
204 
205  if (q.first()) {
206  const QSqlRecord record = q.record();
207  QVariantList row;
208  const int numRecords = record.count();
209  row.reserve(numRecords);
210  for (int i = 0; i < numRecords; ++i) {
211  row << record.fieldName(i);
212  }
213  result << row;
214 
215  int cnt = 0;
216  do {
217  const QSqlRecord record = q.record();
218  QVariantList row;
219  const int numRecords = record.count();
220  row.reserve(numRecords);
221  for (int i = 0; i < numRecords; ++i) {
222  row << record.value(i);
223  }
224  result << row;
225  } while (q.next() && ++cnt < 1000);
226  }
227 
228  const int querySize = query.isSelect() ? query.size() : query.numRowsAffected();
229  Q_EMIT queryExecuted(seq, connectionId, QDateTime::currentMSecsSinceEpoch(),
230  duration, query.executedQuery(), query.boundValues(),
231  querySize, result, QString());
232 
233  if (mFile && mFile->isOpen()) {
234  QTextStream out(mFile.get());
235  out << query.executedQuery() << " " << duration << "ms\n";
236  }
237 
238  // Reset the query
239  q.seek(-1, false);
240 }
QString fieldName(int index) const const
bool isSelect() const const
int numRowsAffected() const const
NETWORKMANAGERQT_EXPORT NetworkManager::Connection::Ptr findConnection(const QString &path)
int size() const const
QVector::iterator begin()
QVariant value(int index) const const
void beginStructure()
KCALENDARCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &)
bool registerObject(const QString &path, QObject *object, QDBusConnection::RegisterOptions options)
QDBusConnection sessionBus()
qint64 currentMSecsSinceEpoch()
QMap< QString, QVariant > boundValues() const const
QString executedQuery() const const
Definition: item.h:44
QSqlError lastError() const const
bool isValid() const const
QString text() const const
QVector::iterator end()
int count() const const
void endStructure()
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jun 5 2020 23:08:56 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.