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