File indexing completed on 2024-04-21 03:51:44
0001 /* 0002 SPDX-FileCopyrightText: 2015 Vishesh Handa <vhanda@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "baloodebug.h" 0008 #include "config.h" 0009 #include "filecontentindexer.h" 0010 #include "filecontentindexerprovider.h" 0011 #include "extractorprocess.h" 0012 0013 #include <QEventLoop> 0014 #include <QElapsedTimer> 0015 #include <QDBusConnection> 0016 0017 using namespace Baloo; 0018 0019 namespace { 0020 // TODO KF6 -- remove/combine with started/finished DBus signal 0021 void sendChangedSignal(const QStringList& updatedFiles) 0022 { 0023 auto message = QDBusMessage::createSignal(QStringLiteral("/files"), 0024 QStringLiteral("org.kde"), 0025 QStringLiteral("changed")); 0026 message.setArguments({updatedFiles}); 0027 QDBusConnection::sessionBus().send(message); 0028 } 0029 } 0030 0031 FileContentIndexer::FileContentIndexer(uint batchSize, 0032 FileContentIndexerProvider* provider, 0033 uint& finishedCount, QObject* parent) 0034 : QObject(parent) 0035 , m_batchSize(batchSize) 0036 , m_provider(provider) 0037 , m_finishedCount(finishedCount) 0038 , m_stop(0) 0039 , m_extractorPath(QStringLiteral(KDE_INSTALL_FULL_LIBEXECDIR_KF "/baloo_file_extractor")) 0040 { 0041 Q_ASSERT(provider); 0042 0043 QDBusConnection bus = QDBusConnection::sessionBus(); 0044 m_monitorWatcher.setConnection(bus); 0045 m_monitorWatcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration); 0046 connect(&m_monitorWatcher, &QDBusServiceWatcher::serviceUnregistered, this, 0047 &FileContentIndexer::monitorClosed); 0048 0049 bus.registerObject(QStringLiteral("/fileindexer"), 0050 this, QDBusConnection::ExportScriptableContents); 0051 } 0052 0053 void FileContentIndexer::run() 0054 { 0055 ExtractorProcess process{m_extractorPath}; 0056 connect(&process, &ExtractorProcess::startedIndexingFile, this, &FileContentIndexer::slotStartedIndexingFile); 0057 connect(&process, &ExtractorProcess::finishedIndexingFile, this, &FileContentIndexer::slotFinishedIndexingFile); 0058 m_stop.storeRelaxed(false); 0059 auto batchSize = m_batchSize; 0060 while (true) { 0061 // 0062 // WARNING: This will go mad, if the Extractor does not commit after N=m_batchSize files 0063 // cause then we will keep fetching the same N files again and again. 0064 // 0065 QVector<quint64> idList = m_provider->fetch(batchSize); 0066 if (idList.isEmpty() || m_stop.loadRelaxed()) { 0067 break; 0068 } 0069 QEventLoop loop; 0070 connect(&process, &ExtractorProcess::done, &loop, &QEventLoop::quit); 0071 0072 bool hadErrors = false; 0073 connect(&process, &ExtractorProcess::failed, &loop, [&hadErrors, &loop]() { hadErrors = true; loop.quit(); }); 0074 0075 uint batchStartCount = m_finishedCount; 0076 connect(&process, &ExtractorProcess::finishedIndexingFile, &loop, [this]() { m_finishedCount++; }); 0077 0078 QElapsedTimer timer; 0079 timer.start(); 0080 0081 process.index(idList); 0082 loop.exec(); 0083 batchSize = idList.size(); 0084 0085 if (hadErrors && !m_stop.loadRelaxed()) { 0086 if (batchSize == 1) { 0087 auto failedId = idList.first(); 0088 auto ok = m_provider->markFailed(failedId); 0089 if (!ok) { 0090 qCCritical(BALOO) << "Not able to commit to DB, DB likely is in a bad state. Exiting"; 0091 exit(1); 0092 } 0093 batchSize = m_batchSize; 0094 } else { 0095 batchSize /= 2; 0096 } 0097 m_updatedFiles.clear(); 0098 // reset to old value - nothing committed 0099 m_finishedCount = batchStartCount; 0100 process.start(); 0101 } else { 0102 // Notify some metadata may have changed 0103 sendChangedSignal(m_updatedFiles); 0104 m_updatedFiles.clear(); 0105 0106 // Update remaining time estimate 0107 auto elapsed = timer.elapsed(); 0108 QMetaObject::invokeMethod(this, 0109 [this, elapsed, batchSize] { committedBatch(elapsed, batchSize); }, 0110 Qt::QueuedConnection); 0111 } 0112 } 0113 QMetaObject::invokeMethod(this, &FileContentIndexer::done, Qt::QueuedConnection); 0114 } 0115 0116 void FileContentIndexer::slotStartedIndexingFile(const QString& filePath) 0117 { 0118 m_currentFile = filePath; 0119 if (!m_registeredMonitors.isEmpty()) { 0120 Q_EMIT startedIndexingFile(filePath); 0121 } 0122 } 0123 0124 void FileContentIndexer::slotFinishedIndexingFile(const QString& filePath, bool fileUpdated) 0125 { 0126 if (fileUpdated) { 0127 m_updatedFiles.append(filePath); 0128 } 0129 0130 m_currentFile = QString(); 0131 if (!m_registeredMonitors.isEmpty()) { 0132 Q_EMIT finishedIndexingFile(filePath); 0133 } 0134 } 0135 0136 void FileContentIndexer::registerMonitor(const QDBusMessage& message) 0137 { 0138 if (!m_registeredMonitors.contains(message.service())) { 0139 m_registeredMonitors << message.service(); 0140 m_monitorWatcher.addWatchedService(message.service()); 0141 } 0142 } 0143 0144 void FileContentIndexer::unregisterMonitor(const QDBusMessage& message) 0145 { 0146 m_registeredMonitors.removeAll(message.service()); 0147 m_monitorWatcher.removeWatchedService(message.service()); 0148 } 0149 0150 void FileContentIndexer::monitorClosed(const QString& service) 0151 { 0152 m_registeredMonitors.removeAll(service); 0153 m_monitorWatcher.removeWatchedService(service); 0154 } 0155 0156 #include "moc_filecontentindexer.cpp"