gui: Begin cancellation of Indexer
这个提交包含在:
		| @@ -129,6 +129,16 @@ void MainWindow::spinPreviewPageValueChanged(int val) | ||||
|  | ||||
| void MainWindow::startIndexing() | ||||
| { | ||||
| 	if(this->indexer->isRunning()) | ||||
| 	{ | ||||
| 		ui->btnStartIndexing->setEnabled(false); | ||||
| 		ui->btnStartIndexing->setText("Start indexing"); | ||||
| 		this->indexer->requestCancellation(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	ui->previewsTab->setEnabled(false); | ||||
| 	ui->resultsTab->setEnabled(false); | ||||
| 	ui->txtPathScanAdd->setEnabled(false); | ||||
| 	ui->txtSearch->setEnabled(false); | ||||
| 	ui->previewProcessBar->setValue(0); | ||||
| @@ -140,6 +150,7 @@ void MainWindow::startIndexing() | ||||
| 	} | ||||
| 	this->indexer->setTargetPaths(paths); | ||||
| 	this->indexer->beginIndexing(); | ||||
| 	ui->btnStartIndexing->setText("Stop indexing"); | ||||
| } | ||||
|  | ||||
| void MainWindow::finishIndexing() | ||||
| @@ -151,6 +162,8 @@ void MainWindow::finishIndexing() | ||||
| 	ui->lblFailedValue->setText(QString::number(result.erroredPaths)); | ||||
| 	ui->lblSkippedValue->setText(QString::number(result.skippedPaths)); | ||||
| 	ui->lblAddedValue->setText(QString::number(result.addedPaths)); | ||||
| 	ui->btnStartIndexing->setEnabled(true); | ||||
| 	ui->btnStartIndexing->setText("Start indexing"); | ||||
| } | ||||
|  | ||||
| void MainWindow::comboScaleChanged(int i) | ||||
|   | ||||
| @@ -66,6 +66,7 @@ class MainWindow : public QMainWindow | ||||
| 	void spinPreviewPageValueChanged(int val); | ||||
| 	void startIndexing(); | ||||
| 	void finishIndexing(); | ||||
| 	void addPathToIndex(); | ||||
| }; | ||||
|  | ||||
| #endif // MAINWINDOW_H | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| #include <QList> | ||||
| #include <QMutex> | ||||
| #include <QSemaphore> | ||||
|  | ||||
| #define QUEUE_SIZE 10000 | ||||
| template <class T> class ConcurrentQueue : protected QList<T> | ||||
| { | ||||
|   | ||||
| @@ -33,6 +33,9 @@ void DirScanWorker::run() | ||||
| 			{ | ||||
| 				if(this->stopToken->load(std::memory_order_relaxed)) | ||||
| 				{ | ||||
| 					Logger::info() << "Received cancel request" << Qt::endl; | ||||
| 					this->results.clear(); | ||||
| 					emit finished(); | ||||
| 					return; | ||||
| 				} | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,12 @@ | ||||
| #include "filescanworker.h" | ||||
| #include "logger.h" | ||||
| FileScanWorker::FileScanWorker(SqliteDbService &db, ConcurrentQueue<QString> &queue, int batchsize) | ||||
| FileScanWorker::FileScanWorker(SqliteDbService &db, ConcurrentQueue<QString> &queue, int batchsize, | ||||
| 							   std::atomic<bool> &stopToken) | ||||
| { | ||||
| 	this->dbService = &db; | ||||
| 	this->queue = &queue; | ||||
| 	this->batchsize = batchsize; | ||||
| 	this->stopToken = &stopToken; | ||||
| } | ||||
|  | ||||
| void FileScanWorker::run() | ||||
| @@ -24,6 +26,11 @@ void FileScanWorker::run() | ||||
| 			sfr = PROCESSFAIL; // well... | ||||
| 		} | ||||
| 		emit result({path, sfr}); | ||||
| 		if(stopToken->load(std::memory_order_relaxed)) // TODO: relaxed should suffice here, but recheck | ||||
| 		{ | ||||
| 			emit finished(); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 	emit finished(); | ||||
| } | ||||
|   | ||||
| @@ -16,9 +16,10 @@ class FileScanWorker : public QObject, public QRunnable | ||||
| 	SqliteDbService *dbService; | ||||
| 	ConcurrentQueue<QString> *queue; | ||||
| 	int batchsize; | ||||
| 	std::atomic<bool> *stopToken; | ||||
|  | ||||
|   public: | ||||
| 	FileScanWorker(SqliteDbService &db, ConcurrentQueue<QString> &queue, int batchsize); | ||||
| 	FileScanWorker(SqliteDbService &db, ConcurrentQueue<QString> &queue, int batchsize, std::atomic<bool> &stopToken); | ||||
| 	void run() override; | ||||
|   signals: | ||||
| 	void result(FileScanResult); | ||||
|   | ||||
| @@ -34,6 +34,7 @@ void Indexer::beginIndexing() | ||||
|  | ||||
| 	this->dirScanner->scan(); | ||||
|  | ||||
| 	this->workerCancellationToken.store(false, std::memory_order_seq_cst); | ||||
| 	launchWorker(this->filePathTargetsQueue, this->filePathTargetsQueue.remaining()); | ||||
| } | ||||
|  | ||||
| @@ -47,6 +48,12 @@ void Indexer::setTargetPaths(QVector<QString> pathsToScan) | ||||
| 	this->pathsToScan = pathsToScan; | ||||
| } | ||||
|  | ||||
| void Indexer::requestCancellation() | ||||
| { | ||||
| 	this->dirScanner->cancel(); | ||||
| 	this->workerCancellationToken.store(true, std::memory_order_release); | ||||
| } | ||||
|  | ||||
| IndexResult Indexer::getResult() | ||||
| { | ||||
| 	return this->currentIndexResult; | ||||
| @@ -55,11 +62,15 @@ IndexResult Indexer::getResult() | ||||
| void Indexer::dirScanFinished() | ||||
| { | ||||
| 	Logger::info() << "Dir scan finished"; | ||||
| 	if(!isRunning()) | ||||
| 	{ | ||||
| 		emit finished(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void Indexer::launchWorker(ConcurrentQueue<QString> &queue, int batchsize) | ||||
| { | ||||
| 	FileScanWorker *runnable = new FileScanWorker(*this->db, queue, batchsize); | ||||
| 	FileScanWorker *runnable = new FileScanWorker(*this->db, queue, batchsize, this->workerCancellationToken); | ||||
| 	connect(runnable, &FileScanWorker::result, this, &Indexer::processFileScanResult); | ||||
| 	connect(runnable, &FileScanWorker::finished, this, &Indexer::processFinishedWorker); | ||||
| 	++this->runningWorkers; | ||||
| @@ -107,10 +118,14 @@ void Indexer::processFileScanResult(FileScanResult result) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool Indexer::isRunning() | ||||
| { | ||||
| 	return this->runningWorkers > 0 || this->dirScanner->isRunning(); | ||||
| } | ||||
| void Indexer::processFinishedWorker() | ||||
| { | ||||
| 	--this->runningWorkers; | ||||
| 	if(this->runningWorkers == 0 && !this->dirScanner->isRunning()) | ||||
| 	if(!isRunning()) | ||||
| 	{ | ||||
| 		emit finished(); | ||||
| 	} | ||||
|   | ||||
| @@ -51,21 +51,25 @@ class Indexer : public QObject | ||||
|  | ||||
| 	QVector<QString> pathsToScan; | ||||
| 	QSharedPointer<ParallelDirScanner> dirScanner; | ||||
| 	QSharedPointer<FileScanWorker> fileScanner; | ||||
|  | ||||
| 	QStringList ignorePattern; | ||||
|  | ||||
| 	/* Those path pointing to files not directories */ | ||||
| 	ConcurrentQueue<QString> filePathTargetsQueue; | ||||
|  | ||||
| 	std::atomic<bool> workerCancellationToken; | ||||
| 	IndexResult currentIndexResult; | ||||
| 	void launchWorker(ConcurrentQueue<QString> &queue, int batchsize); | ||||
|  | ||||
|   public: | ||||
| 	bool isRunning(); | ||||
|  | ||||
| 	void beginIndexing(); | ||||
| 	void setIgnorePattern(QStringList ignorePattern); | ||||
| 	void setTargetPaths(QVector<QString> pathsToScan); | ||||
|  | ||||
| 	void requestCancellation(); | ||||
|  | ||||
| 	Indexer(SqliteDbService &db); | ||||
| 	IndexResult getResult(); | ||||
|  | ||||
|   | ||||
| @@ -31,12 +31,13 @@ void ParallelDirScanner::setPaths(QVector<QString> paths) | ||||
|  | ||||
| void ParallelDirScanner::cancel() | ||||
| { | ||||
| 	this->stopToken.store(true, std::memory_order_relaxed); | ||||
| 	this->stopToken.store(true, std::memory_order_seq_cst); | ||||
| } | ||||
|  | ||||
| void ParallelDirScanner::handleWorkersProgress(unsigned int progress) | ||||
| { | ||||
| 	this->processedPaths += progress; | ||||
| 	if(!this->stopToken.load(std::memory_order_seq_cst)) | ||||
| 		emit this->progress(progress, this->processedPaths); | ||||
| } | ||||
|  | ||||
| @@ -45,7 +46,7 @@ void ParallelDirScanner::handleWorkersFinish() | ||||
| 	Logger::info() << "Worker finished"; | ||||
| 	// no mutexes required due to queued connection | ||||
| 	++finishedWorkers; | ||||
| 	if(finishedWorkers == getThreadsNum()) | ||||
| 	if(this->stopToken.load(std::memory_order_seq_cst) || finishedWorkers == getThreadsNum()) | ||||
| 	{ | ||||
| 		running = false; | ||||
| 		emit scanComplete(); | ||||
|   | ||||
		在新工单中引用
	
	屏蔽一个用户