Changeset View
Changeset View
Standalone View
Standalone View
src/file/fileindexscheduler.cpp
Show All 36 Lines | |||||
37 | #include <QDBusConnection> | 37 | #include <QDBusConnection> | ||
38 | 38 | | |||
39 | using namespace Baloo; | 39 | using namespace Baloo; | ||
40 | 40 | | |||
41 | FileIndexScheduler::FileIndexScheduler(Database* db, FileIndexerConfig* config, QObject* parent) | 41 | FileIndexScheduler::FileIndexScheduler(Database* db, FileIndexerConfig* config, QObject* parent) | ||
42 | : QObject(parent) | 42 | : QObject(parent) | ||
43 | , m_db(db) | 43 | , m_db(db) | ||
44 | , m_config(config) | 44 | , m_config(config) | ||
45 | , m_indexerStates(QList<Baloo::IndexerState>() << Idle) | ||||
45 | , m_provider(db) | 46 | , m_provider(db) | ||
46 | , m_contentIndexer(nullptr) | 47 | , m_contentIndexer(nullptr) | ||
47 | , m_indexerState(Idle) | | |||
48 | , m_timeEstimator(config, this) | 48 | , m_timeEstimator(config, this) | ||
49 | , m_checkUnindexedFiles(false) | 49 | , m_checkUnindexedFiles(false) | ||
50 | , m_checkStaleIndexEntries(false) | 50 | , m_checkStaleIndexEntries(false) | ||
51 | , m_schedulerLocked(false) | ||||
51 | { | 52 | { | ||
52 | Q_ASSERT(db); | 53 | Q_ASSERT(db); | ||
53 | Q_ASSERT(config); | 54 | Q_ASSERT(config); | ||
54 | 55 | | |||
55 | m_threadPool.setMaxThreadCount(1); | | |||
56 | | ||||
57 | connect(&m_powerMonitor, &PowerStateMonitor::powerManagementStatusChanged, | 56 | connect(&m_powerMonitor, &PowerStateMonitor::powerManagementStatusChanged, | ||
58 | this, &FileIndexScheduler::powerManagementStatusChanged); | 57 | this, &FileIndexScheduler::suspendContentIndexer); | ||
59 | 58 | | |||
60 | m_contentIndexer = new FileContentIndexer(m_config, &m_provider, this); | 59 | m_contentIndexer = new FileContentIndexer(m_config, &m_provider, this); | ||
61 | m_contentIndexer->setAutoDelete(false); | 60 | m_contentIndexer->setAutoDelete(false); | ||
62 | connect(m_contentIndexer, &FileContentIndexer::done, this, | | |||
63 | &FileIndexScheduler::scheduleIndexing); | | |||
64 | connect(m_contentIndexer, &FileContentIndexer::newBatchTime, &m_timeEstimator, | 61 | connect(m_contentIndexer, &FileContentIndexer::newBatchTime, &m_timeEstimator, | ||
65 | &TimeEstimator::handleNewBatchTime); | 62 | &TimeEstimator::handleNewBatchTime); | ||
66 | 63 | | |||
67 | QDBusConnection::sessionBus().registerObject(QStringLiteral("/scheduler"), | 64 | QDBusConnection::sessionBus().registerObject(QStringLiteral("/scheduler"), | ||
68 | this, QDBusConnection::ExportScriptableContents); | 65 | this, QDBusConnection::ExportScriptableContents); | ||
69 | } | 66 | } | ||
70 | 67 | | |||
71 | FileIndexScheduler::~FileIndexScheduler() | 68 | FileIndexScheduler::~FileIndexScheduler() | ||
72 | { | 69 | { | ||
73 | m_threadPool.waitForDone(0); // wait 0 msecs | 70 | m_threadPool.waitForDone(0); // wait 0 msecs | ||
74 | } | 71 | } | ||
75 | 72 | | |||
76 | void FileIndexScheduler::scheduleIndexing() | 73 | void FileIndexScheduler::scheduleIndexing() | ||
77 | { | 74 | { | ||
78 | if (m_threadPool.activeThreadCount() || m_indexerState == Suspended) { | 75 | if (m_schedulerLocked) { | ||
79 | return; | 76 | return; | ||
80 | } | 77 | } | ||
81 | 78 | | |||
82 | if (m_config->isInitialRun()) { | 79 | auto runnableStarted = [=] (Baloo::IndexerState state) { | ||
80 | m_indexerStates.prepend(state); | ||||
81 | | ||||
82 | Q_EMIT stateChanged(m_indexerStates.at(0)); | ||||
83 | }; | ||||
84 | | ||||
85 | auto runnableStopped = [=] (Baloo::IndexerState state) { | ||||
86 | m_schedulerLocked = false; | ||||
87 | m_indexerStates.removeOne(state); | ||||
88 | | ||||
89 | Q_EMIT stateChanged(m_indexerStates.at(0)); | ||||
90 | scheduleIndexing(); | ||||
91 | }; | ||||
92 | | ||||
93 | if (m_config->isInitialRun() && !m_indexerStates.contains(FirstRun)) { | ||||
83 | auto runnable = new FirstRunIndexer(m_db, m_config, m_config->includeFolders()); | 94 | auto runnable = new FirstRunIndexer(m_db, m_config, m_config->includeFolders()); | ||
84 | connect(runnable, &FirstRunIndexer::done, this, &FileIndexScheduler::scheduleIndexing); | 95 | connect(runnable, &FirstRunIndexer::done, this, [=] () { | ||
96 | runnableStopped(FirstRun); | ||||
97 | }); | ||||
85 | 98 | | |||
99 | m_schedulerLocked = true; | ||||
86 | m_threadPool.start(runnable); | 100 | m_threadPool.start(runnable); | ||
87 | m_indexerState = FirstRun; | 101 | runnableStarted(FirstRun); | ||
88 | Q_EMIT stateChanged(m_indexerState); | | |||
89 | return; | | |||
90 | } | 102 | } | ||
91 | 103 | | |||
92 | if (!m_newFiles.isEmpty()) { | 104 | if (m_checkUnindexedFiles && !m_indexerStates.contains(UnindexedFileCheck)) { | ||
93 | auto runnable = new NewFileIndexer(m_db, m_config, m_newFiles); | 105 | auto runnable = new UnindexedFileIndexer(m_db, m_config); | ||
94 | connect(runnable, &NewFileIndexer::done, this, &FileIndexScheduler::scheduleIndexing); | 106 | connect(runnable, &UnindexedFileIndexer::done, this, [=] () { | ||
107 | m_checkUnindexedFiles = false; | ||||
108 | runnableStopped(UnindexedFileCheck); | ||||
109 | }); | ||||
95 | 110 | | |||
111 | m_schedulerLocked = true; | ||||
96 | m_threadPool.start(runnable); | 112 | m_threadPool.start(runnable); | ||
97 | m_newFiles.clear(); | 113 | runnableStarted(UnindexedFileCheck); | ||
98 | m_indexerState = NewFiles; | | |||
99 | Q_EMIT stateChanged(m_indexerState); | | |||
100 | return; | | |||
bruns: You sneak in a unmentioned and significant change - you allow to run several indexer tasks to… | |||||
101 | } | 114 | } | ||
102 | 115 | | |||
103 | if (!m_modifiedFiles.isEmpty()) { | 116 | if (m_checkStaleIndexEntries && !m_indexerStates.contains(StaleIndexEntriesClean)) { | ||
104 | auto runnable = new ModifiedFileIndexer(m_db, m_config, m_modifiedFiles); | 117 | auto runnable = new IndexCleaner(m_db, m_config); | ||
105 | connect(runnable, &ModifiedFileIndexer::done, this, &FileIndexScheduler::scheduleIndexing); | 118 | connect(runnable, &IndexCleaner::done, this, [=] () { | ||
119 | m_checkStaleIndexEntries = false; | ||||
120 | runnableStopped(StaleIndexEntriesClean); | ||||
121 | }); | ||||
106 | 122 | | |||
107 | m_threadPool.start(runnable); | 123 | m_threadPool.start(runnable); | ||
108 | m_modifiedFiles.clear(); | 124 | runnableStarted(StaleIndexEntriesClean); | ||
bruns: Whats that supposed to do (I have an idea, but thats ugly ...) | |||||
This starts a QRunnable at a negative priority (in this case the negative integer value for NewFiles) and then calls runnableStarted(NewFiles) with the enum of the started runnable. smithjd: This starts a QRunnable at a negative priority (in this case the negative integer value for… | |||||
Yeah, I suspected that - fugly as hell! If you need different priorities, make it explicit. bruns: Yeah, I suspected that - fugly as hell!
If you need different priorities, make it explicit. | |||||
109 | m_indexerState = ModifiedFiles; | | |||
110 | Q_EMIT stateChanged(m_indexerState); | | |||
111 | return; | | |||
112 | } | 125 | } | ||
113 | 126 | | |||
114 | if (!m_xattrFiles.isEmpty()) { | 127 | if (!m_newFiles.isEmpty() && !m_indexerStates.contains(NewFiles)) { | ||
115 | auto runnable = new XAttrIndexer(m_db, m_config, m_xattrFiles); | 128 | auto runnable = new NewFileIndexer(m_db, m_config, m_newFiles); | ||
116 | connect(runnable, &XAttrIndexer::done, this, &FileIndexScheduler::scheduleIndexing); | 129 | connect(runnable, &NewFileIndexer::done, this, [=] () { | ||
130 | m_newFiles.clear(); | ||||
131 | runnableStopped(NewFiles); | ||||
132 | }); | ||||
117 | 133 | | |||
118 | m_threadPool.start(runnable); | 134 | m_threadPool.start(runnable); | ||
119 | m_xattrFiles.clear(); | 135 | runnableStarted(NewFiles); | ||
120 | m_indexerState = XAttrFiles; | | |||
121 | Q_EMIT stateChanged(m_indexerState); | | |||
122 | return; | | |||
123 | } | 136 | } | ||
124 | 137 | | |||
125 | if (m_provider.size() && !m_powerMonitor.isOnBattery()) { | 138 | if (!m_xattrFiles.isEmpty() && !m_indexerStates.contains(XAttrFiles)) { | ||
126 | m_threadPool.start(m_contentIndexer); | 139 | auto runnable = new XAttrIndexer(m_db, m_config, m_xattrFiles); | ||
127 | m_indexerState = ContentIndexing; | 140 | connect(runnable, &XAttrIndexer::done, this, [=] () { | ||
128 | Q_EMIT stateChanged(m_indexerState); | 141 | m_xattrFiles.clear(); | ||
129 | return; | 142 | runnableStopped(XAttrFiles); | ||
143 | }); | ||||
144 | | ||||
145 | m_threadPool.start(runnable); | ||||
146 | runnableStarted(XAttrFiles); | ||||
130 | } | 147 | } | ||
131 | 148 | | |||
132 | if (m_checkUnindexedFiles) { | 149 | if (!m_modifiedFiles.isEmpty() && !m_indexerStates.contains(ModifiedFiles)) { | ||
133 | auto runnable = new UnindexedFileIndexer(m_db, m_config); | 150 | auto runnable = new ModifiedFileIndexer(m_db, m_config, m_modifiedFiles); | ||
134 | connect(runnable, &UnindexedFileIndexer::done, this, &FileIndexScheduler::scheduleIndexing); | 151 | connect(runnable, &ModifiedFileIndexer::done, this, [=] () { | ||
152 | m_modifiedFiles.clear(); | ||||
153 | runnableStopped(ModifiedFiles); | ||||
154 | }); | ||||
135 | 155 | | |||
136 | m_threadPool.start(runnable); | 156 | m_threadPool.start(runnable); | ||
137 | m_checkUnindexedFiles = false; | 157 | runnableStarted(ModifiedFiles); | ||
138 | m_indexerState = UnindexedFileCheck; | | |||
139 | Q_EMIT stateChanged(m_indexerState); | | |||
140 | return; | | |||
141 | } | 158 | } | ||
142 | 159 | | |||
143 | if (m_checkStaleIndexEntries) { | 160 | if ((m_provider.size() > 0) | ||
144 | auto runnable = new IndexCleaner(m_db, m_config); | 161 | && !m_indexerStates.contains(ContentIndexing) | ||
145 | connect(runnable, &IndexCleaner::done, this, &FileIndexScheduler::scheduleIndexing); | 162 | && !m_indexerStates.contains(Suspended)) { | ||
163 | connect(m_contentIndexer, &FileContentIndexer::done, this, [=] () { | ||||
164 | runnableStopped(ContentIndexing); | ||||
165 | }); | ||||
146 | 166 | | |||
147 | m_threadPool.start(runnable); | 167 | m_threadPool.start(m_contentIndexer); | ||
148 | m_checkStaleIndexEntries = false; | 168 | runnableStarted(ContentIndexing); | ||
149 | m_indexerState = StaleIndexEntriesClean; | | |||
150 | Q_EMIT stateChanged(m_indexerState); | | |||
151 | return; | | |||
152 | } | 169 | } | ||
153 | m_indexerState = Idle; | | |||
154 | Q_EMIT stateChanged(m_indexerState); | | |||
155 | } | 170 | } | ||
156 | 171 | | |||
157 | static void removeStartsWith(QStringList& list, const QString& dir) | 172 | static void removeStartsWith(QStringList& list, const QString& dir) | ||
158 | { | 173 | { | ||
159 | const auto tail = std::remove_if(list.begin(), list.end(), | 174 | const auto tail = std::remove_if(list.begin(), list.end(), | ||
160 | [&dir](const QString& file) { | 175 | [&dir](const QString& file) { | ||
161 | return file.startsWith(dir); | 176 | return file.startsWith(dir); | ||
162 | }); | 177 | }); | ||
163 | list.erase(tail, list.end()); | 178 | list.erase(tail, list.end()); | ||
164 | } | 179 | } | ||
165 | 180 | | |||
166 | void FileIndexScheduler::handleFileRemoved(const QString& file) | 181 | void FileIndexScheduler::handleFileRemoved(const QString& file) | ||
167 | { | 182 | { | ||
168 | if (!file.endsWith(QLatin1Char('/'))) { | 183 | if (!file.endsWith(QLatin1Char('/'))) { | ||
169 | m_newFiles.removeOne(file); | 184 | m_newFiles.removeOne(file); | ||
170 | m_modifiedFiles.removeOne(file); | 185 | m_modifiedFiles.removeOne(file); | ||
171 | m_xattrFiles.removeOne(file); | 186 | m_xattrFiles.removeOne(file); | ||
172 | } | 187 | } else { | ||
173 | else { | | |||
174 | removeStartsWith(m_newFiles, file); | 188 | removeStartsWith(m_newFiles, file); | ||
175 | removeStartsWith(m_modifiedFiles, file); | 189 | removeStartsWith(m_modifiedFiles, file); | ||
176 | removeStartsWith(m_xattrFiles, file); | 190 | removeStartsWith(m_xattrFiles, file); | ||
177 | } | 191 | } | ||
178 | } | 192 | } | ||
179 | 193 | | |||
180 | void FileIndexScheduler::powerManagementStatusChanged(bool isOnBattery) | 194 | void FileIndexScheduler::suspendContentIndexer(bool suspend) | ||
181 | { | 195 | { | ||
182 | qDebug() << "Power state changed"; | 196 | if (suspend && !m_indexerStates.contains(Suspended)) { | ||
183 | if (isOnBattery && m_indexerState == ContentIndexing) { | 197 | qDebug() << "Suspending content indexing"; | ||
184 | qDebug() << "On battery stopping content indexer"; | | |||
185 | m_contentIndexer->quit(); | | |||
186 | //TODO: Maybe we can add a special state for suspended due to being on battery. | | |||
187 | m_indexerState = Idle; | | |||
188 | Q_EMIT stateChanged(m_indexerState); | | |||
189 | } else if (!isOnBattery) { | | |||
190 | scheduleIndexing(); | | |||
191 | } | | |||
192 | } | | |||
193 | 198 | | |||
194 | void FileIndexScheduler::setSuspend(bool suspend) | 199 | m_indexerStates.prepend(Suspended); | ||
195 | { | | |||
196 | if (suspend) { | | |||
197 | qDebug() << "Suspending"; | | |||
198 | if (m_indexerState == ContentIndexing) { | | |||
199 | m_contentIndexer->quit(); | 200 | m_contentIndexer->quit(); | ||
200 | } | 201 | } else if (m_indexerStates.contains(Suspended)) { | ||
201 | m_indexerState = Suspended; | 202 | qDebug() << "Resuming content indexing"; | ||
202 | Q_EMIT stateChanged(m_indexerState); | 203 | | ||
203 | } else { | 204 | m_indexerStates.removeOne(Suspended); | ||
204 | qDebug() << "Resuming"; | | |||
205 | m_indexerState = Idle; | | |||
206 | // No need to emit here we'll be emitting in scheduling | | |||
207 | scheduleIndexing(); | 205 | scheduleIndexing(); | ||
208 | } | 206 | } | ||
209 | } | 207 | } | ||
210 | 208 | | |||
211 | uint FileIndexScheduler::getRemainingTime() | 209 | uint FileIndexScheduler::getRemainingTime() | ||
212 | { | 210 | { | ||
213 | if (m_indexerState != ContentIndexing) { | 211 | if (m_indexerStates.at(0) != ContentIndexing) { | ||
214 | return 0; | 212 | return 0; | ||
215 | } | 213 | } | ||
216 | return m_timeEstimator.calculateTimeLeft(m_provider.size()); | 214 | return m_timeEstimator.calculateTimeLeft(m_provider.size()); | ||
217 | } | 215 | } | ||
218 | 216 | | |||
219 | void FileIndexScheduler::scheduleCheckUnindexedFiles() | 217 | void FileIndexScheduler::scheduleCheckUnindexedFiles() | ||
220 | { | 218 | { | ||
221 | m_checkUnindexedFiles = true; | 219 | m_checkUnindexedFiles = true; | ||
Show All 24 Lines |
You sneak in a unmentioned and significant change - you allow to run several indexer tasks to run in parallel!