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