Baloo

filecontentindexer.cpp
1/*
2 SPDX-FileCopyrightText: 2015 Vishesh Handa <vhanda@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-or-later
5*/
6
7#include "baloodebug.h"
8#include "config.h"
9#include "filecontentindexer.h"
10#include "filecontentindexerprovider.h"
11#include "extractorprocess.h"
12
13#include <QEventLoop>
14#include <QElapsedTimer>
15#include <QDBusConnection>
16
17using namespace Baloo;
18
19namespace {
20 // TODO KF6 -- remove/combine with started/finished DBus signal
21 void sendChangedSignal(const QStringList& updatedFiles)
22 {
23 auto message = QDBusMessage::createSignal(QStringLiteral("/files"),
24 QStringLiteral("org.kde"),
25 QStringLiteral("changed"));
26 message.setArguments({updatedFiles});
28 }
29}
30
31FileContentIndexer::FileContentIndexer(uint batchSize,
32 FileContentIndexerProvider* provider,
33 uint& finishedCount, QObject* parent)
34 : QObject(parent)
35 , m_batchSize(batchSize)
36 , m_provider(provider)
37 , m_finishedCount(finishedCount)
38 , m_stop(0)
39 , m_extractorPath(QStringLiteral(KDE_INSTALL_FULL_LIBEXECDIR_KF "/baloo_file_extractor"))
40{
41 Q_ASSERT(provider);
42
44 m_monitorWatcher.setConnection(bus);
45 m_monitorWatcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
46 connect(&m_monitorWatcher, &QDBusServiceWatcher::serviceUnregistered, this,
47 &FileContentIndexer::monitorClosed);
48
49 bus.registerObject(QStringLiteral("/fileindexer"),
51}
52
53void FileContentIndexer::run()
54{
55 ExtractorProcess process{m_extractorPath};
56 connect(&process, &ExtractorProcess::startedIndexingFile, this, &FileContentIndexer::slotStartedIndexingFile);
57 connect(&process, &ExtractorProcess::finishedIndexingFile, this, &FileContentIndexer::slotFinishedIndexingFile);
58 m_stop.storeRelaxed(false);
59 auto batchSize = m_batchSize;
60 while (true) {
61 //
62 // WARNING: This will go mad, if the Extractor does not commit after N=m_batchSize files
63 // cause then we will keep fetching the same N files again and again.
64 //
65 QVector<quint64> idList = m_provider->fetch(batchSize);
66 if (idList.isEmpty() || m_stop.loadRelaxed()) {
67 break;
68 }
69 QEventLoop loop;
70 connect(&process, &ExtractorProcess::done, &loop, &QEventLoop::quit);
71
72 bool hadErrors = false;
73 connect(&process, &ExtractorProcess::failed, &loop, [&hadErrors, &loop]() { hadErrors = true; loop.quit(); });
74
75 uint batchStartCount = m_finishedCount;
76 connect(&process, &ExtractorProcess::finishedIndexingFile, &loop, [this]() { m_finishedCount++; });
77
78 QElapsedTimer timer;
79 timer.start();
80
81 process.index(idList);
82 loop.exec();
83 batchSize = idList.size();
84
85 if (hadErrors && !m_stop.loadRelaxed()) {
86 if (batchSize == 1) {
87 auto failedId = idList.first();
88 auto ok = m_provider->markFailed(failedId);
89 if (!ok) {
90 qCCritical(BALOO) << "Not able to commit to DB, DB likely is in a bad state. Exiting";
91 exit(1);
92 }
93 batchSize = m_batchSize;
94 } else {
95 batchSize /= 2;
96 }
97 m_updatedFiles.clear();
98 // reset to old value - nothing committed
99 m_finishedCount = batchStartCount;
100 process.start();
101 } else {
102 // Notify some metadata may have changed
103 sendChangedSignal(m_updatedFiles);
104 m_updatedFiles.clear();
105
106 // Update remaining time estimate
107 auto elapsed = timer.elapsed();
109 [this, elapsed, batchSize] { committedBatch(elapsed, batchSize); },
111 }
112 }
113 QMetaObject::invokeMethod(this, &FileContentIndexer::done, Qt::QueuedConnection);
114}
115
116void FileContentIndexer::slotStartedIndexingFile(const QString& filePath)
117{
118 m_currentFile = filePath;
119 if (!m_registeredMonitors.isEmpty()) {
120 Q_EMIT startedIndexingFile(filePath);
121 }
122}
123
124void FileContentIndexer::slotFinishedIndexingFile(const QString& filePath, bool fileUpdated)
125{
126 if (fileUpdated) {
127 m_updatedFiles.append(filePath);
128 }
129
130 m_currentFile = QString();
131 if (!m_registeredMonitors.isEmpty()) {
132 Q_EMIT finishedIndexingFile(filePath);
133 }
134}
135
136void FileContentIndexer::registerMonitor(const QDBusMessage& message)
137{
138 if (!m_registeredMonitors.contains(message.service())) {
139 m_registeredMonitors << message.service();
140 m_monitorWatcher.addWatchedService(message.service());
141 }
142}
143
144void FileContentIndexer::unregisterMonitor(const QDBusMessage& message)
145{
146 m_registeredMonitors.removeAll(message.service());
147 m_monitorWatcher.removeWatchedService(message.service());
148}
149
150void FileContentIndexer::monitorClosed(const QString& service)
151{
152 m_registeredMonitors.removeAll(service);
153 m_monitorWatcher.removeWatchedService(service);
154}
155
156#include "moc_filecontentindexer.cpp"
Implements storage for docIds without any associated data Instantiated for:
Definition coding.cpp:11
T loadRelaxed() const const
void storeRelaxed(T newValue)
bool registerObject(const QString &path, QObject *object, RegisterOptions options)
bool send(const QDBusMessage &message) const const
QDBusConnection sessionBus()
QDBusMessage createSignal(const QString &path, const QString &interface, const QString &name)
QString service() const const
void addWatchedService(const QString &newService)
bool removeWatchedService(const QString &service)
void serviceUnregistered(const QString &serviceName)
int exec(ProcessEventsFlags flags)
void quit()
void append(QList< T > &&value)
void clear()
T & first()
bool isEmpty() const const
qsizetype removeAll(const AT &t)
qsizetype size() const const
bool invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret)
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QueuedConnection
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 16:56:58 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.