/* * Copyright (C) 2022, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #include "index-scheduler.h" #include "index-updater.h" using namespace UkuiSearch; IndexScheduler::IndexScheduler(QObject *parent) : QObject(parent), m_statusRecorder(IndexStatusRecorder::getInstance()), m_config(FileIndexerConfig::getInstance()), m_state(Startup), m_stop(0) { qRegisterMetaType("IndexerState"); m_threadPool.setMaxThreadCount(1); connect(&m_fileWatcher, &FileWatcher::filesUpdate, this, &IndexScheduler::updateIndex); connect(m_config, &FileIndexerConfig::fileIndexEnableStatusChanged, this, &IndexScheduler::fileIndexEnable); connect(m_config, &FileIndexerConfig::appendIndexDir, this, &IndexScheduler::addNewPath); connect(m_config, &FileIndexerConfig::removeIndexDir, this, &IndexScheduler::removeIndex); m_state = Startup; if(m_config->isFileIndexEnable()) { scheduleIndexing(); } else { m_stop.fetchAndStoreRelaxed(1); } } void IndexScheduler::addNewPath(const QString &folders, const QStringList &blackList) { if(m_stop.load()) { qDebug() << "Index Scheduler is being stopped, add operation will be executed when started up next time."; return; } m_isAddNewPathFinished = false; m_state = Running; FirstRunIndexer::Targets target = FirstRunIndexer::Target::None; if(m_config->isFileIndexEnable()) { target |= FirstRunIndexer::Target::Basic; } if(m_config->isContentIndexEnable()) { target |= FirstRunIndexer::Target::Content; } if(FirstRunIndexer::Target::None != target) { FirstRunIndexer *indexer = new FirstRunIndexer(QStringList(folders), blackList, m_stop, FirstRunIndexer::WorkMode::Add, target); connect(indexer, &FirstRunIndexer::done, this, &IndexScheduler::addNewPathFinished, Qt::QueuedConnection); m_threadPool.start(indexer); } } void IndexScheduler::removeIndex(const QString &folders) { if(m_stop.load()) { qDebug() << "Index Scheduler is being stopped, remove operation will be executed when started up next time."; return; } m_fileWatcher.removeWatch(folders, true); } void IndexScheduler::stop() { m_stop.fetchAndStoreRelaxed(1); m_fileWatcher.removeWatch(); m_threadPool.clear(); m_state = Stop; qDebug() << "Index scheduler has been stopped."; Q_EMIT stateChange(m_state); } void IndexScheduler::scheduleIndexing() { if(!m_isFirstRunFinished) { return; } m_isFirstRunFinished = false; m_stop.fetchAndStoreRelaxed(0); m_state = Running; Q_EMIT stateChange(m_state); FirstRunIndexer::Targets rebuiltTarget = checkAndRebuild(); FirstRunIndexer::WorkModes mode = FirstRunIndexer::WorkMode::Update; FirstRunIndexer::Targets target = FirstRunIndexer::Target::None; //如果数据库被执行过重建,那么跳过增量更新步骤。 if(m_config->isFileIndexEnable() && !(rebuiltTarget & FirstRunIndexer::Target::Basic)) { target |= FirstRunIndexer::Target::Basic; m_statusRecorder->setStatus(INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Updating); } if(m_config->isContentIndexEnable() && !(rebuiltTarget & FirstRunIndexer::Target::Content)) { target |= FirstRunIndexer::Target::Content; m_statusRecorder->setStatus(CONTENT_INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Updating); } startIndexJob(mode, target); //启动监听 m_fileWatcher.installWatches(); } IndexScheduler::IndexerState IndexScheduler::getIndexState() { return m_state; } FirstRunIndexer::Targets IndexScheduler::checkAndRebuild() { FirstRunIndexer::WorkModes mode = FirstRunIndexer::WorkMode::Rebuild; FirstRunIndexer::Targets target = FirstRunIndexer::Target::None; if((m_statusRecorder->getStatus(INDEX_DATABASE_STATE_KEY).toInt() == IndexStatusRecorder::State::Error || !m_statusRecorder->versionCheck(INDEX_DATABASE_VERSION_KEY, INDEX_DATABASE_VERSION)) && m_config->isFileIndexEnable()) { qDebug() << "Basic database need rebuild"; target |= FirstRunIndexer::Target::Basic; m_statusRecorder->setStatus(INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Initializing); } if((m_statusRecorder->getStatus(CONTENT_INDEX_DATABASE_STATE_KEY).toInt() == IndexStatusRecorder::State::Error || !m_statusRecorder->versionCheck(CONTENT_DATABASE_VERSION_KEY, CONTENT_DATABASE_VERSION)) && m_config->isFileIndexEnable()) { qDebug() << "Content database need rebuild"; target |= FirstRunIndexer::Target::Content; m_statusRecorder->setStatus(INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Initializing); } startIndexJob(mode, target); return target; } void IndexScheduler::startIndexJob(FirstRunIndexer::WorkModes &mode, FirstRunIndexer::Targets &target) { if(FirstRunIndexer::Target::None != target) { FirstRunIndexer *indexer = new FirstRunIndexer(m_config->currentIndexableDir(), m_config->currentBlackListOfIndex(), m_stop, mode, target); connect(indexer, &FirstRunIndexer::done, this, &IndexScheduler::firstRunFinished, Qt::QueuedConnection); connect(indexer, &FirstRunIndexer::progress, this, &IndexScheduler::process); connect(indexer, &FirstRunIndexer::basicIndexDone, this, [&](uint size){ bool success = false; if(!(m_statusRecorder->getStatus(INDEX_DATABASE_STATE_KEY).toInt() == IndexStatusRecorder::State::Error)) { m_statusRecorder->setStatus(INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Ready); success = true; } Q_EMIT basicIndexDone(size, success); }); connect(indexer, &FirstRunIndexer::contentIndexDone, this, [&](uint size){ bool success = false; if(!(m_statusRecorder->getStatus(CONTENT_INDEX_DATABASE_STATE_KEY).toInt() == IndexStatusRecorder::State::Error)) { m_statusRecorder->setStatus(CONTENT_INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Ready); success = true; } Q_EMIT contentIndexDone(size, success); }); m_threadPool.start(indexer); } } void IndexScheduler::fileIndexEnable(bool enable) { if(enable) { scheduleIndexing(); } else { stop(); } } void IndexScheduler::updateIndex(const QVector &files) { qDebug() << "updateIndex====="; m_isUpdateFinished = false; m_state = Running; IndexUpdater *updateJob = new IndexUpdater(files, m_stop); connect(updateJob, &IndexUpdater::done, this, &IndexScheduler::updateFinished, Qt::QueuedConnection); m_threadPool.start(updateJob); } void IndexScheduler::firstRunFinished() { if((m_statusRecorder->getStatus(INDEX_DATABASE_STATE_KEY).toInt() == IndexStatusRecorder::State::Ready) && m_statusRecorder->getStatus(CONTENT_INDEX_DATABASE_STATE_KEY).toInt() == IndexStatusRecorder::State::Ready) { m_isFirstRunFinished = true; } if(m_isFirstRunFinished && m_isAddNewPathFinished && m_isUpdateFinished) { m_state = Idle; Q_EMIT stateChange(m_state); } } void IndexScheduler::updateFinished() { m_isUpdateFinished = true; if(m_isFirstRunFinished && m_isAddNewPathFinished) { m_state = Idle; Q_EMIT stateChange(m_state); } } void IndexScheduler::addNewPathFinished() { m_isAddNewPathFinished = true; if(m_isFirstRunFinished && m_isUpdateFinished) { m_state = Idle; Q_EMIT stateChange(m_state); } }