mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 05:49:53 +08:00
Searcher: use async first phase search
This commit is contained in:
parent
0e4442f513
commit
486950c1aa
@ -9,7 +9,7 @@
|
||||
using namespace vnotex;
|
||||
|
||||
FileSearchEngineWorker::FileSearchEngineWorker(QObject *p_parent)
|
||||
: QThread(p_parent)
|
||||
: AsyncWorker(p_parent)
|
||||
{
|
||||
}
|
||||
|
||||
@ -22,16 +22,6 @@ void FileSearchEngineWorker::setData(const QVector<SearchSecondPhaseItem> &p_ite
|
||||
m_token = p_token;
|
||||
}
|
||||
|
||||
void FileSearchEngineWorker::stop()
|
||||
{
|
||||
m_askedToStop.store(1);
|
||||
}
|
||||
|
||||
bool FileSearchEngineWorker::isAskedToStop() const
|
||||
{
|
||||
return m_askedToStop.load() == 1;
|
||||
}
|
||||
|
||||
void FileSearchEngineWorker::run()
|
||||
{
|
||||
const int c_batchSize = 100;
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include <QAtomicInt>
|
||||
#include <QVector>
|
||||
|
||||
#include <utils/asyncworker.h>
|
||||
|
||||
#include "searchtoken.h"
|
||||
#include "searchdata.h"
|
||||
|
||||
@ -15,7 +17,7 @@ namespace vnotex
|
||||
{
|
||||
struct SearchResultItem;
|
||||
|
||||
class FileSearchEngineWorker : public QThread
|
||||
class FileSearchEngineWorker : public AsyncWorker
|
||||
{
|
||||
Q_OBJECT
|
||||
friend class FileSearchEngine;
|
||||
@ -28,9 +30,6 @@ namespace vnotex
|
||||
const QSharedPointer<SearchOption> &p_option,
|
||||
const SearchToken &p_token);
|
||||
|
||||
public slots:
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
void resultItemsReady(const QVector<QSharedPointer<SearchResultItem>> &p_items);
|
||||
|
||||
@ -44,10 +43,6 @@ namespace vnotex
|
||||
|
||||
void processBatchResults();
|
||||
|
||||
bool isAskedToStop() const;
|
||||
|
||||
QAtomicInt m_askedToStop = 0;
|
||||
|
||||
QVector<SearchSecondPhaseItem> m_items;
|
||||
|
||||
SearchToken m_token;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <core/exception.h>
|
||||
#include <notebook/node.h>
|
||||
#include <notebook/notebook.h>
|
||||
#include <utils/asyncworker.h>
|
||||
|
||||
#include "searchresultitem.h"
|
||||
#include "filesearchengine.h"
|
||||
@ -53,25 +54,31 @@ SearchState Searcher::search(const QSharedPointer<SearchOption> &p_option, const
|
||||
|
||||
emit logRequested(tr("Searching %n buffer(s)", "", p_buffers.size()));
|
||||
|
||||
emit progressUpdated(0, p_buffers.size());
|
||||
for (int i = 0; i < p_buffers.size(); ++i) {
|
||||
if (!p_buffers[i]) {
|
||||
continue;
|
||||
m_firstPhaseWorker->doWork([this, p_buffers]() {
|
||||
emit progressUpdated(0, p_buffers.size());
|
||||
for (int i = 0; i < p_buffers.size(); ++i) {
|
||||
if (!p_buffers[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isAskedToStop()) {
|
||||
emit finished(SearchState::Stopped);
|
||||
return;
|
||||
}
|
||||
|
||||
auto file = p_buffers[i]->getFile();
|
||||
if (!firstPhaseSearch(file.data())) {
|
||||
emit finished(SearchState::Failed);
|
||||
return;
|
||||
}
|
||||
|
||||
emit progressUpdated(i + 1, p_buffers.size());
|
||||
}
|
||||
|
||||
if (isAskedToStop()) {
|
||||
return SearchState::Stopped;
|
||||
}
|
||||
emit finished(SearchState::Finished);
|
||||
});
|
||||
|
||||
auto file = p_buffers[i]->getFile();
|
||||
if (!firstPhaseSearch(file.data())) {
|
||||
return SearchState::Failed;
|
||||
}
|
||||
|
||||
emit progressUpdated(i + 1, p_buffers.size());
|
||||
}
|
||||
|
||||
return SearchState::Finished;
|
||||
return SearchState::Busy;
|
||||
}
|
||||
|
||||
SearchState Searcher::search(const QSharedPointer<SearchOption> &p_option, Node *p_folder)
|
||||
@ -88,29 +95,19 @@ SearchState Searcher::search(const QSharedPointer<SearchOption> &p_option, Node
|
||||
|
||||
emit logRequested(tr("Searching folder (%1)").arg(p_folder->getName()));
|
||||
|
||||
QVector<SearchSecondPhaseItem> secondPhaseItems;
|
||||
if (!firstPhaseSearchFolder(p_folder, secondPhaseItems)) {
|
||||
return SearchState::Failed;
|
||||
}
|
||||
|
||||
if (isAskedToStop()) {
|
||||
return SearchState::Stopped;
|
||||
}
|
||||
|
||||
if (!secondPhaseItems.isEmpty()) {
|
||||
// Do second phase search.
|
||||
if (!secondPhaseSearch(secondPhaseItems)) {
|
||||
return SearchState::Failed;
|
||||
m_firstPhaseWorker->doWork([this, p_folder]() {
|
||||
if (!firstPhaseSearchFolder(p_folder, m_secondPhaseItems)) {
|
||||
m_secondPhaseItems.clear();
|
||||
emit finished(SearchState::Failed);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAskedToStop()) {
|
||||
return SearchState::Stopped;
|
||||
if (m_secondPhaseItems.isEmpty()) {
|
||||
emit finished(SearchState::Finished);
|
||||
}
|
||||
});
|
||||
|
||||
return SearchState::Busy;
|
||||
}
|
||||
|
||||
return SearchState::Finished;
|
||||
return SearchState::Busy;
|
||||
}
|
||||
|
||||
SearchState Searcher::search(const QSharedPointer<SearchOption> &p_option, const QVector<Notebook *> &p_notebooks)
|
||||
@ -119,41 +116,32 @@ SearchState Searcher::search(const QSharedPointer<SearchOption> &p_option, const
|
||||
return SearchState::Failed;
|
||||
}
|
||||
|
||||
QVector<SearchSecondPhaseItem> secondPhaseItems;
|
||||
m_firstPhaseWorker->doWork([this, p_notebooks]() {
|
||||
emit progressUpdated(0, p_notebooks.size());
|
||||
for (int i = 0; i < p_notebooks.size(); ++i) {
|
||||
if (isAskedToStop()) {
|
||||
m_secondPhaseItems.clear();
|
||||
emit finished(SearchState::Stopped);
|
||||
return;
|
||||
}
|
||||
|
||||
emit progressUpdated(0, p_notebooks.size());
|
||||
for (int i = 0; i < p_notebooks.size(); ++i) {
|
||||
if (isAskedToStop()) {
|
||||
return SearchState::Stopped;
|
||||
emit logRequested(tr("Searching notebook (%1)").arg(p_notebooks[i]->getName()));
|
||||
|
||||
if (!firstPhaseSearch(p_notebooks[i], m_secondPhaseItems)) {
|
||||
m_secondPhaseItems.clear();
|
||||
emit finished(SearchState::Failed);
|
||||
return;
|
||||
}
|
||||
|
||||
emit progressUpdated(i + 1, p_notebooks.size());
|
||||
}
|
||||
|
||||
emit logRequested(tr("Searching notebook (%1)").arg(p_notebooks[i]->getName()));
|
||||
|
||||
if (!firstPhaseSearch(p_notebooks[i], secondPhaseItems)) {
|
||||
return SearchState::Failed;
|
||||
if (m_secondPhaseItems.isEmpty()) {
|
||||
emit finished(SearchState::Finished);
|
||||
}
|
||||
});
|
||||
|
||||
emit progressUpdated(i + 1, p_notebooks.size());
|
||||
}
|
||||
|
||||
if (isAskedToStop()) {
|
||||
return SearchState::Stopped;
|
||||
}
|
||||
|
||||
if (!secondPhaseItems.isEmpty()) {
|
||||
// Do second phase search.
|
||||
if (!secondPhaseSearch(secondPhaseItems)) {
|
||||
return SearchState::Failed;
|
||||
}
|
||||
|
||||
if (isAskedToStop()) {
|
||||
return SearchState::Stopped;
|
||||
}
|
||||
|
||||
return SearchState::Busy;
|
||||
}
|
||||
|
||||
return SearchState::Finished;
|
||||
return SearchState::Busy;
|
||||
}
|
||||
|
||||
bool Searcher::prepare(const QSharedPointer<SearchOption> &p_option)
|
||||
@ -172,12 +160,24 @@ bool Searcher::prepare(const QSharedPointer<SearchOption> &p_option)
|
||||
m_filePattern = QRegularExpression(QRegularExpression::wildcardToRegularExpression(m_option->m_filePattern), QRegularExpression::CaseInsensitiveOption);
|
||||
}
|
||||
|
||||
if (!m_firstPhaseWorker) {
|
||||
m_firstPhaseWorker = new AsyncWorkerWithFunctor(this);
|
||||
connect(m_firstPhaseWorker, &AsyncWorkerWithFunctor::finished,
|
||||
this, &Searcher::doSecondPhaseSearch);
|
||||
}
|
||||
|
||||
if (m_firstPhaseWorker->isRunning()) {
|
||||
emit logRequested(tr("Failed to search due to worker is busy"));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_secondPhaseItems.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Searcher::isAskedToStop() const
|
||||
{
|
||||
QCoreApplication::sendPostedEvents();
|
||||
return m_askedToStop;
|
||||
}
|
||||
|
||||
@ -357,7 +357,7 @@ bool Searcher::firstPhaseSearchFolder(Node *p_node, QVector<SearchSecondPhaseIte
|
||||
return false;
|
||||
}
|
||||
|
||||
if (testTarget(SearchTarget::SearchFolder)) {
|
||||
if (testTarget(SearchTarget::SearchFolder) && !p_node->isRoot()) {
|
||||
const auto name = p_node->getName();
|
||||
const auto folderPath = p_node->fetchAbsolutePath();
|
||||
const auto relativePath = p_node->fetchPath();
|
||||
@ -531,3 +531,26 @@ bool Searcher::searchTag(const Node *p_node) const
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Searcher::doSecondPhaseSearch()
|
||||
{
|
||||
if (m_secondPhaseItems.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAskedToStop()) {
|
||||
emit finished(SearchState::Stopped);
|
||||
return;
|
||||
}
|
||||
|
||||
// Do second phase search.
|
||||
if (!secondPhaseSearch(m_secondPhaseItems)) {
|
||||
emit finished(SearchState::Failed);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAskedToStop()) {
|
||||
emit finished(SearchState::Stopped);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <QSharedPointer>
|
||||
#include <QScopedPointer>
|
||||
#include <QRegularExpression>
|
||||
#include <QThread>
|
||||
|
||||
#include "searchdata.h"
|
||||
#include "searchtoken.h"
|
||||
@ -17,6 +18,7 @@ namespace vnotex
|
||||
struct SearchResultItem;
|
||||
class Node;
|
||||
class Notebook;
|
||||
class AsyncWorkerWithFunctor;
|
||||
|
||||
class Searcher : public QObject
|
||||
{
|
||||
@ -83,6 +85,9 @@ namespace vnotex
|
||||
|
||||
void createSearchEngine();
|
||||
|
||||
// Will be called after m_firstPhaseWorker finished.
|
||||
void doSecondPhaseSearch();
|
||||
|
||||
QSharedPointer<SearchOption> m_option;
|
||||
|
||||
SearchToken m_token;
|
||||
@ -92,6 +97,11 @@ namespace vnotex
|
||||
bool m_askedToStop = false;
|
||||
|
||||
QScopedPointer<ISearchEngine> m_engine;
|
||||
|
||||
AsyncWorkerWithFunctor *m_firstPhaseWorker = nullptr;
|
||||
|
||||
// Pending second phase items.
|
||||
QVector<SearchSecondPhaseItem> m_secondPhaseItems;
|
||||
};
|
||||
}
|
||||
|
||||
|
37
src/utils/asyncworker.cpp
Normal file
37
src/utils/asyncworker.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include "asyncworker.h"
|
||||
|
||||
using namespace vnotex;
|
||||
|
||||
AsyncWorker::AsyncWorker(QObject *p_parent)
|
||||
: QThread(p_parent)
|
||||
{
|
||||
}
|
||||
|
||||
void AsyncWorker::stop()
|
||||
{
|
||||
m_askedToStop.store(1);
|
||||
}
|
||||
|
||||
bool AsyncWorker::isAskedToStop() const
|
||||
{
|
||||
return m_askedToStop.load() == 1;
|
||||
}
|
||||
|
||||
|
||||
AsyncWorkerWithFunctor::AsyncWorkerWithFunctor(QObject *p_parent)
|
||||
: QThread(p_parent)
|
||||
{
|
||||
}
|
||||
|
||||
void AsyncWorkerWithFunctor::doWork(const Functor &p_functor)
|
||||
{
|
||||
Q_ASSERT(!isRunning());
|
||||
m_functor = p_functor;
|
||||
start();
|
||||
}
|
||||
|
||||
void AsyncWorkerWithFunctor::run()
|
||||
{
|
||||
Q_ASSERT(m_functor);
|
||||
m_functor();
|
||||
}
|
44
src/utils/asyncworker.h
Normal file
44
src/utils/asyncworker.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef ASYNCWORKER_H
|
||||
#define ASYNCWORKER_H
|
||||
|
||||
#include <QThread>
|
||||
#include <QAtomicInt>
|
||||
|
||||
namespace vnotex
|
||||
{
|
||||
class AsyncWorker : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AsyncWorker(QObject *p_parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void stop();
|
||||
|
||||
protected:
|
||||
bool isAskedToStop() const;
|
||||
|
||||
private:
|
||||
QAtomicInt m_askedToStop = 0;
|
||||
};
|
||||
|
||||
|
||||
class AsyncWorkerWithFunctor : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
typedef std::function<void()> Functor;
|
||||
|
||||
explicit AsyncWorkerWithFunctor(QObject *p_parent = nullptr);
|
||||
|
||||
void doWork(const Functor &p_functor);
|
||||
|
||||
protected:
|
||||
void run() Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
Functor m_functor;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ASYNCWORKER_H
|
@ -1,6 +1,7 @@
|
||||
QT += widgets svg
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/asyncworker.cpp \
|
||||
$$PWD/callbackpool.cpp \
|
||||
$$PWD/contentmediautils.cpp \
|
||||
$$PWD/docsutils.cpp \
|
||||
@ -18,6 +19,7 @@ SOURCES += \
|
||||
$$PWD/clipboardutils.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/asyncworker.h \
|
||||
$$PWD/callbackpool.h \
|
||||
$$PWD/contentmediautils.h \
|
||||
$$PWD/docsutils.h \
|
||||
|
@ -40,6 +40,10 @@ SearchPanel::SearchPanel(const QSharedPointer<ISearchInfoProvider> &p_provider,
|
||||
{
|
||||
qRegisterMetaType<QVector<QSharedPointer<SearchResultItem>>>("QVector<QSharedPointer<SearchResultItem>>");
|
||||
|
||||
qRegisterMetaType<QSharedPointer<SearchResultItem>>("QSharedPointer<SearchResultItem>");
|
||||
|
||||
qRegisterMetaType<SearchState>("SearchState");
|
||||
|
||||
setupUI();
|
||||
|
||||
initOptions();
|
||||
@ -442,9 +446,6 @@ SearchState SearchPanel::search(const QSharedPointer<SearchOption> &p_option)
|
||||
break;
|
||||
}
|
||||
auto folder = m_provider->getCurrentFolder();
|
||||
if (folder && (folder->isRoot())) {
|
||||
folder = nullptr;
|
||||
}
|
||||
if (!folder) {
|
||||
break;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user