File indexing completed on 2024-12-22 04:52:57
0001 /* 0002 * This file is part of the KDE Akonadi Search Project 0003 * SPDX-FileCopyrightText: 2013 Vishesh Handa <me@vhanda.in> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 * 0007 */ 0008 0009 #include "emailindexer.h" 0010 0011 #include <QApplication> 0012 #include <QDebug> 0013 #include <QElapsedTimer> 0014 #include <QFile> 0015 #include <QTimer> 0016 0017 #include <Akonadi/Collection> 0018 #include <Akonadi/CollectionFetchJob> 0019 #include <Akonadi/Item> 0020 #include <Akonadi/ItemFetchJob> 0021 #include <Akonadi/ItemFetchScope> 0022 #include <chrono> 0023 0024 using namespace std::chrono_literals; 0025 class App : public QApplication 0026 { 0027 Q_OBJECT 0028 public: 0029 App(int &argc, char **argv, int flags = ApplicationFlags); 0030 0031 private Q_SLOTS: 0032 void main(); 0033 0034 void slotRootCollectionsFetched(KJob *job); 0035 void indexNextCollection(); 0036 void itemReceived(const Akonadi::Item::List &item); 0037 void slotIndexed(); 0038 void slotCommitTimerElapsed(); 0039 0040 private: 0041 Akonadi::Collection::List m_collections; 0042 EmailIndexer m_indexer; 0043 0044 QElapsedTimer m_totalTime; 0045 int m_indexTime; 0046 int m_numEmails; 0047 0048 QTimer m_commitTimer; 0049 }; 0050 0051 int main(int argc, char **argv) 0052 { 0053 App app(argc, argv); 0054 return app.exec(); 0055 } 0056 0057 App::App(int &argc, char **argv, int flags) 0058 : QApplication(argc, argv, flags) 0059 , m_indexer(QStringLiteral("/tmp/xap"), QStringLiteral("/tmp/xapC")) 0060 { 0061 QTimer::singleShot(0, this, &App::main); 0062 } 0063 0064 void App::main() 0065 { 0066 m_commitTimer.setInterval(1s); 0067 connect(&m_commitTimer, &QTimer::timeout, this, &App::slotCommitTimerElapsed); 0068 m_commitTimer.start(); 0069 0070 auto job = new Akonadi::CollectionFetchJob(Akonadi::Collection::root(), Akonadi::CollectionFetchJob::Recursive); 0071 connect(job, &Akonadi::CollectionFetchJob::finished, this, &App::slotRootCollectionsFetched); 0072 job->start(); 0073 0074 m_numEmails = 0; 0075 m_indexTime = 0; 0076 m_totalTime.start(); 0077 } 0078 0079 void App::slotRootCollectionsFetched(KJob *kjob) 0080 { 0081 auto job = qobject_cast<Akonadi::CollectionFetchJob *>(kjob); 0082 m_collections = job->collections(); 0083 0084 QMutableListIterator<Akonadi::Collection> it(m_collections); 0085 while (it.hasNext()) { 0086 const Akonadi::Collection &c = it.next(); 0087 const QStringList mimeTypes = c.contentMimeTypes(); 0088 if (!c.contentMimeTypes().contains(QLatin1StringView("message/rfc822"))) { 0089 it.remove(); 0090 } 0091 } 0092 0093 if (!m_collections.isEmpty()) { 0094 indexNextCollection(); 0095 } else { 0096 qDebug() << "No collections to index"; 0097 } 0098 } 0099 0100 void App::indexNextCollection() 0101 { 0102 auto fetchJob = new Akonadi::ItemFetchJob(m_collections.takeFirst(), this); 0103 fetchJob->fetchScope().fetchAllAttributes(true); 0104 fetchJob->fetchScope().fetchFullPayload(true); 0105 fetchJob->fetchScope().setFetchModificationTime(false); 0106 fetchJob->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent); 0107 fetchJob->setDeliveryOption(Akonadi::ItemFetchJob::EmitItemsIndividually); 0108 0109 connect(fetchJob, &Akonadi::ItemFetchJob::itemsReceived, this, &App::itemReceived); 0110 connect(fetchJob, &Akonadi::ItemFetchJob::result, this, &App::slotIndexed); 0111 } 0112 0113 void App::itemReceived(const Akonadi::Item::List &itemList) 0114 { 0115 QElapsedTimer timer; 0116 timer.start(); 0117 0118 for (const Akonadi::Item &item : itemList) { 0119 m_indexer.index(item); 0120 } 0121 0122 m_indexTime += timer.elapsed(); 0123 m_numEmails += itemList.size(); 0124 } 0125 0126 void App::slotCommitTimerElapsed() 0127 { 0128 QElapsedTimer timer; 0129 timer.start(); 0130 0131 m_indexer.commit(); 0132 m_indexTime += timer.elapsed(); 0133 0134 qDebug() << "Emails:" << m_numEmails; 0135 qDebug() << "Total Time:" << m_totalTime.elapsed() / 1000.0 << " seconds"; 0136 qDebug() << "Index Time:" << m_indexTime / 1000.0 << " seconds"; 0137 } 0138 0139 void App::slotIndexed() 0140 { 0141 if (!m_collections.isEmpty()) { 0142 QTimer::singleShot(0, this, &App::indexNextCollection); 0143 return; 0144 } 0145 0146 m_indexer.commit(); 0147 0148 qDebug() << "Emails:" << m_numEmails; 0149 qDebug() << "Total Time:" << m_totalTime.elapsed() / 1000.0 << " seconds"; 0150 qDebug() << "Index Time:" << m_indexTime / 1000.0 << " seconds"; 0151 0152 // Print the io usage 0153 QFile file(QStringLiteral("/proc/self/io")); 0154 file.open(QIODevice::ReadOnly | QIODevice::Text); 0155 0156 QTextStream fs(&file); 0157 QString str = fs.readAll(); 0158 0159 qDebug() << "------- IO ---------"; 0160 QTextStream stream(&str); 0161 while (!stream.atEnd()) { 0162 QString str = stream.readLine(); 0163 0164 QString rchar(QStringLiteral("rchar: ")); 0165 if (str.startsWith(rchar)) { 0166 ulong amt = QStringView(str).mid(rchar.size()).toULong(); 0167 qDebug() << "Read:" << amt / 1024 << "kb"; 0168 } 0169 0170 QString wchar(QStringLiteral("wchar: ")); 0171 if (str.startsWith(wchar)) { 0172 ulong amt = QStringView(str).mid(wchar.size()).toULong(); 0173 qDebug() << "Write:" << amt / 1024 << "kb"; 0174 } 0175 0176 QString read(QStringLiteral("read_bytes: ")); 0177 if (str.startsWith(read)) { 0178 ulong amt = QStringView(str).mid(read.size()).toULong(); 0179 qDebug() << "Actual Reads:" << amt / 1024 << "kb"; 0180 } 0181 0182 QString write(QStringLiteral("write_bytes: ")); 0183 if (str.startsWith(write)) { 0184 ulong amt = QStringView(str).mid(write.size()).toULong(); 0185 qDebug() << "Actual Writes:" << amt / 1024 << "kb"; 0186 } 0187 } 0188 qDebug() << "\nThe actual read/writes may be 0 because of an existing" 0189 << "cache and /tmp being memory mapped"; 0190 quit(); 0191 } 0192 0193 #include "emailtest.moc"