diff --git a/src/file/fileindexscheduler.cpp b/src/file/fileindexscheduler.cpp index 50ae0e55..bb661bbd 100644 --- a/src/file/fileindexscheduler.cpp +++ b/src/file/fileindexscheduler.cpp @@ -1,283 +1,286 @@ /* * Copyright (C) 2015 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "fileindexscheduler.h" #include "baloodebug.h" #include "firstrunindexer.h" #include "newfileindexer.h" #include "modifiedfileindexer.h" #include "xattrindexer.h" #include "filecontentindexer.h" #include "filecontentindexerprovider.h" #include "unindexedfileindexer.h" #include "indexcleaner.h" #include "fileindexerconfig.h" #include #include #include using namespace Baloo; FileIndexScheduler::FileIndexScheduler(Database* db, FileIndexerConfig* config, QObject* parent) : QObject(parent) , m_db(db) , m_config(config) , m_provider(db) , m_contentIndexer(nullptr) , m_indexerState(Idle) , m_timeEstimator(config, this) , m_checkUnindexedFiles(false) , m_checkStaleIndexEntries(false) , m_isGoingIdle(false) { Q_ASSERT(db); Q_ASSERT(config); m_threadPool.setMaxThreadCount(1); connect(&m_powerMonitor, &PowerStateMonitor::powerManagementStatusChanged, this, &FileIndexScheduler::powerManagementStatusChanged); + if (m_powerMonitor.isOnBattery()) { + m_indexerState = LowPowerIdle; + } + m_contentIndexer = new FileContentIndexer(m_config, &m_provider, this); m_contentIndexer->setAutoDelete(false); connect(m_contentIndexer, &FileContentIndexer::done, this, &FileIndexScheduler::runnerFinished); connect(m_contentIndexer, &FileContentIndexer::newBatchTime, &m_timeEstimator, &TimeEstimator::handleNewBatchTime); QDBusConnection::sessionBus().registerObject(QStringLiteral("/scheduler"), this, QDBusConnection::ExportScriptableContents); } FileIndexScheduler::~FileIndexScheduler() { m_threadPool.waitForDone(0); // wait 0 msecs } void FileIndexScheduler::scheduleIndexing() { - if (!m_isGoingIdle && m_indexerState != Idle) { + if (!isIndexerIdle()) { return; } m_isGoingIdle = false; if (m_config->isInitialRun()) { auto runnable = new FirstRunIndexer(m_db, m_config, m_config->includeFolders()); connect(runnable, &FirstRunIndexer::done, this, &FileIndexScheduler::runnerFinished); m_threadPool.start(runnable); m_indexerState = FirstRun; Q_EMIT stateChanged(m_indexerState); return; } if (!m_newFiles.isEmpty()) { auto runnable = new NewFileIndexer(m_db, m_config, m_newFiles); connect(runnable, &NewFileIndexer::done, this, &FileIndexScheduler::runnerFinished); m_threadPool.start(runnable); m_newFiles.clear(); m_indexerState = NewFiles; Q_EMIT stateChanged(m_indexerState); return; } if (!m_modifiedFiles.isEmpty()) { auto runnable = new ModifiedFileIndexer(m_db, m_config, m_modifiedFiles); connect(runnable, &ModifiedFileIndexer::done, this, &FileIndexScheduler::runnerFinished); m_threadPool.start(runnable); m_modifiedFiles.clear(); m_indexerState = ModifiedFiles; Q_EMIT stateChanged(m_indexerState); return; } if (!m_xattrFiles.isEmpty()) { auto runnable = new XAttrIndexer(m_db, m_config, m_xattrFiles); connect(runnable, &XAttrIndexer::done, this, &FileIndexScheduler::runnerFinished); m_threadPool.start(runnable); m_xattrFiles.clear(); m_indexerState = XAttrFiles; Q_EMIT stateChanged(m_indexerState); return; } // No housekeeping, no content indexing if (m_powerMonitor.isOnBattery()) { - if (m_indexerState != Idle) { - m_indexerState = Idle; + if (m_indexerState != LowPowerIdle) { + m_indexerState = LowPowerIdle; Q_EMIT stateChanged(m_indexerState); } return; } // This has to be above content indexing, because there can be files that // should not be indexed in the DB (i.e. if config was changed) if (m_checkStaleIndexEntries) { auto runnable = new IndexCleaner(m_db, m_config); connect(runnable, &IndexCleaner::done, this, &FileIndexScheduler::runnerFinished); m_threadPool.start(runnable); m_checkStaleIndexEntries = false; m_indexerState = StaleIndexEntriesClean; Q_EMIT stateChanged(m_indexerState); return; } if (m_provider.size()) { m_threadPool.start(m_contentIndexer); m_indexerState = ContentIndexing; Q_EMIT stateChanged(m_indexerState); return; } if (m_checkUnindexedFiles) { auto runnable = new UnindexedFileIndexer(m_db, m_config); connect(runnable, &UnindexedFileIndexer::done, this, &FileIndexScheduler::runnerFinished); m_threadPool.start(runnable); m_checkUnindexedFiles = false; m_indexerState = UnindexedFileCheck; Q_EMIT stateChanged(m_indexerState); return; } if (m_indexerState != Idle) { m_indexerState = Idle; Q_EMIT stateChanged(m_indexerState); } } static void removeStartsWith(QStringList& list, const QString& dir) { const auto tail = std::remove_if(list.begin(), list.end(), [&dir](const QString& file) { return file.startsWith(dir); }); list.erase(tail, list.end()); } static void removeShouldNotIndex(QStringList& list, FileIndexerConfig* config) { const auto tail = std::remove_if(list.begin(), list.end(), [config](const QString& file) { return !config->shouldBeIndexed(file); }); list.erase(tail, list.end()); } void FileIndexScheduler::updateConfig() { // Interrupt content indexer, to avoid indexing files that should // not be indexed (bug 373430) if (m_indexerState == ContentIndexing) { m_contentIndexer->quit(); } removeShouldNotIndex(m_newFiles, m_config); removeShouldNotIndex(m_modifiedFiles, m_config); removeShouldNotIndex(m_xattrFiles, m_config); m_checkStaleIndexEntries = true; m_checkUnindexedFiles = true; scheduleIndexing(); } void FileIndexScheduler::handleFileRemoved(const QString& file) { if (!file.endsWith(QLatin1Char('/'))) { m_newFiles.removeOne(file); m_modifiedFiles.removeOne(file); m_xattrFiles.removeOne(file); } else { removeStartsWith(m_newFiles, file); removeStartsWith(m_modifiedFiles, file); removeStartsWith(m_xattrFiles, file); } } void FileIndexScheduler::powerManagementStatusChanged(bool isOnBattery) { qCDebug(BALOO) << "Power state changed - onBattery:" << isOnBattery; if (isOnBattery && m_indexerState == ContentIndexing) { qCDebug(BALOO) << "On battery, stopping content indexer"; m_contentIndexer->quit(); - //TODO: Maybe we can add a special state for suspended due to being on battery. } else if (!isOnBattery) { scheduleIndexing(); } } void FileIndexScheduler::setSuspend(bool suspend) { if (suspend) { qCDebug(BALOO) << "Suspending"; if (m_indexerState == ContentIndexing) { m_contentIndexer->quit(); } m_indexerState = Suspended; Q_EMIT stateChanged(m_indexerState); } else { qCDebug(BALOO) << "Resuming"; m_indexerState = Idle; // No need to emit here we'll be emitting in scheduling scheduleIndexing(); } } uint FileIndexScheduler::getRemainingTime() { if (m_indexerState != ContentIndexing) { return 0; } return m_timeEstimator.calculateTimeLeft(m_provider.size()); } void FileIndexScheduler::scheduleCheckUnindexedFiles() { m_checkUnindexedFiles = true; } void FileIndexScheduler::checkUnindexedFiles() { m_checkUnindexedFiles = true; scheduleIndexing(); } void FileIndexScheduler::scheduleCheckStaleIndexEntries() { m_checkStaleIndexEntries = true; } void FileIndexScheduler::checkStaleIndexEntries() { m_checkStaleIndexEntries = true; scheduleIndexing(); } uint FileIndexScheduler::getBatchSize() { return m_config->maxUncomittedFiles(); } diff --git a/src/file/fileindexscheduler.h b/src/file/fileindexscheduler.h index 13f42584..a77f2cb6 100644 --- a/src/file/fileindexscheduler.h +++ b/src/file/fileindexscheduler.h @@ -1,130 +1,135 @@ /* * Copyright (C) 2015 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef BALOO_FILEINDEXSCHEDULER_H #define BALOO_FILEINDEXSCHEDULER_H #include #include #include #include #include "filecontentindexerprovider.h" #include "powerstatemonitor.h" #include "indexerstate.h" #include "timeestimator.h" namespace Baloo { class Database; class FileIndexerConfig; class FileContentIndexer; class FileIndexScheduler : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.baloo.scheduler") Q_PROPERTY(int state READ state NOTIFY stateChanged) public: FileIndexScheduler(Database* db, FileIndexerConfig* config, QObject* parent = nullptr); ~FileIndexScheduler() override; int state() const { return m_indexerState; } Q_SIGNALS: Q_SCRIPTABLE void stateChanged(int state); public Q_SLOTS: void indexNewFile(const QString& file) { if (!m_newFiles.contains(file)) { m_newFiles << file; - if (m_indexerState == Idle || m_isGoingIdle) { + if (isIndexerIdle()) { QTimer::singleShot(0, this, &FileIndexScheduler::scheduleIndexing); } } } void indexModifiedFile(const QString& file) { if (!m_modifiedFiles.contains(file)) { m_modifiedFiles << file; - if (m_indexerState == Idle || m_isGoingIdle) { + if (isIndexerIdle()) { QTimer::singleShot(0, this, &FileIndexScheduler::scheduleIndexing); } } } void indexXAttrFile(const QString& file) { if (!m_xattrFiles.contains(file)) { m_xattrFiles << file; - if (m_indexerState == Idle || m_isGoingIdle) { + if (isIndexerIdle()) { QTimer::singleShot(0, this, &FileIndexScheduler::scheduleIndexing); } } } void runnerFinished() { m_isGoingIdle = true; QTimer::singleShot(0, this, &FileIndexScheduler::scheduleIndexing); } void handleFileRemoved(const QString& file); void updateConfig(); void scheduleIndexing(); void scheduleCheckUnindexedFiles(); void scheduleCheckStaleIndexEntries(); Q_SCRIPTABLE void suspend() { setSuspend(true); } Q_SCRIPTABLE void resume() { setSuspend(false); } Q_SCRIPTABLE uint getRemainingTime(); Q_SCRIPTABLE void checkUnindexedFiles(); Q_SCRIPTABLE void checkStaleIndexEntries(); Q_SCRIPTABLE uint getBatchSize(); private Q_SLOTS: void powerManagementStatusChanged(bool isOnBattery); private: void setSuspend(bool suspend); + bool isIndexerIdle() { + return m_isGoingIdle || + (m_indexerState == Idle) || + (m_indexerState == LowPowerIdle); + } Database* m_db; FileIndexerConfig* m_config; QStringList m_newFiles; QStringList m_modifiedFiles; QStringList m_xattrFiles; QThreadPool m_threadPool; FileContentIndexerProvider m_provider; FileContentIndexer* m_contentIndexer; PowerStateMonitor m_powerMonitor; IndexerState m_indexerState; TimeEstimator m_timeEstimator; bool m_checkUnindexedFiles; bool m_checkStaleIndexEntries; bool m_isGoingIdle; }; } #endif // BALOO_FILEINDEXSCHEDULER_H diff --git a/src/file/indexerstate.h b/src/file/indexerstate.h index 74e973d4..bf0811bb 100644 --- a/src/file/indexerstate.h +++ b/src/file/indexerstate.h @@ -1,82 +1,87 @@ /* * This file is part of the KDE Baloo Project * Copyright (C) 2015 Pinak Ahuja * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #ifndef BALOO_INDEXER_STATE_H #define BALOO_INDEXER_STATE_H #include #include namespace Baloo { enum IndexerState { Idle, Suspended, FirstRun, NewFiles, ModifiedFiles, XAttrFiles, ContentIndexing, UnindexedFileCheck, - StaleIndexEntriesClean + StaleIndexEntriesClean, + LowPowerIdle, }; inline QString stateString(IndexerState state) { QString status = i18n("Unknown"); switch (state) { case Idle: status = i18n("Idle"); break; case Suspended: status = i18n("Suspended"); break; case FirstRun: status = i18n("Initial Indexing"); break; case NewFiles: status = i18n("Indexing new files"); break; case ModifiedFiles: status = i18n("Indexing modified files"); break; case XAttrFiles: status = i18n("Indexing Extended Attributes"); break; case ContentIndexing: status = i18n("Indexing file content"); break; case UnindexedFileCheck: status = i18n("Checking for unindexed files"); break; case StaleIndexEntriesClean: status = i18n("Checking for stale index entries"); + break; + case LowPowerIdle: + status = i18n("Idle (Powersave)"); + break; } return status; } //TODO: check for implicit conversion inline QString stateString(int state) { return stateString(static_cast(state)); } } #endif //BALOO_INDEXER_STATE_H