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"