Baloo

filecontentindexer.cpp
1 /*
2  SPDX-FileCopyrightText: 2015 Vishesh Handa <[email protected]>
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 
17 using namespace Baloo;
18 
19 namespace {
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 
31 FileContentIndexer::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 "/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 
53 void 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 
116 void FileContentIndexer::slotStartedIndexingFile(const QString& filePath)
117 {
118  m_currentFile = filePath;
119  if (!m_registeredMonitors.isEmpty()) {
120  Q_EMIT startedIndexingFile(filePath);
121  }
122 }
123 
124 void 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 
136 void 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 
144 void FileContentIndexer::unregisterMonitor(const QDBusMessage& message)
145 {
146  m_registeredMonitors.removeAll(message.service());
147  m_monitorWatcher.removeWatchedService(message.service());
148 }
149 
150 void FileContentIndexer::monitorClosed(const QString& service)
151 {
152  m_registeredMonitors.removeAll(service);
153  m_monitorWatcher.removeWatchedService(service);
154 }
155 
156 #include "moc_filecontentindexer.cpp"
bool isEmpty() const const
bool registerObject(const QString &path, QObject *object, QDBusConnection::RegisterOptions options)
int exec(QEventLoop::ProcessEventsFlags flags)
T & first()
void serviceUnregistered(const QString &serviceName)
bool send(const QDBusMessage &message) const const
QDBusConnection sessionBus()
void quit()
Implements storage for docIds without any associated data Instantiated for:
Definition: coding.cpp:11
QueuedConnection
QDBusMessage createSignal(const QString &path, const QString &interface, const QString &name)
bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9)
int size() const const
QString message
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Wed Nov 29 2023 03:56:26 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.