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;
|
using namespace vnotex;
|
||||||
|
|
||||||
FileSearchEngineWorker::FileSearchEngineWorker(QObject *p_parent)
|
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;
|
m_token = p_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSearchEngineWorker::stop()
|
|
||||||
{
|
|
||||||
m_askedToStop.store(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FileSearchEngineWorker::isAskedToStop() const
|
|
||||||
{
|
|
||||||
return m_askedToStop.load() == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileSearchEngineWorker::run()
|
void FileSearchEngineWorker::run()
|
||||||
{
|
{
|
||||||
const int c_batchSize = 100;
|
const int c_batchSize = 100;
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#include <QAtomicInt>
|
#include <QAtomicInt>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
|
#include <utils/asyncworker.h>
|
||||||
|
|
||||||
#include "searchtoken.h"
|
#include "searchtoken.h"
|
||||||
#include "searchdata.h"
|
#include "searchdata.h"
|
||||||
|
|
||||||
@ -15,7 +17,7 @@ namespace vnotex
|
|||||||
{
|
{
|
||||||
struct SearchResultItem;
|
struct SearchResultItem;
|
||||||
|
|
||||||
class FileSearchEngineWorker : public QThread
|
class FileSearchEngineWorker : public AsyncWorker
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
friend class FileSearchEngine;
|
friend class FileSearchEngine;
|
||||||
@ -28,9 +30,6 @@ namespace vnotex
|
|||||||
const QSharedPointer<SearchOption> &p_option,
|
const QSharedPointer<SearchOption> &p_option,
|
||||||
const SearchToken &p_token);
|
const SearchToken &p_token);
|
||||||
|
|
||||||
public slots:
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void resultItemsReady(const QVector<QSharedPointer<SearchResultItem>> &p_items);
|
void resultItemsReady(const QVector<QSharedPointer<SearchResultItem>> &p_items);
|
||||||
|
|
||||||
@ -44,10 +43,6 @@ namespace vnotex
|
|||||||
|
|
||||||
void processBatchResults();
|
void processBatchResults();
|
||||||
|
|
||||||
bool isAskedToStop() const;
|
|
||||||
|
|
||||||
QAtomicInt m_askedToStop = 0;
|
|
||||||
|
|
||||||
QVector<SearchSecondPhaseItem> m_items;
|
QVector<SearchSecondPhaseItem> m_items;
|
||||||
|
|
||||||
SearchToken m_token;
|
SearchToken m_token;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <core/exception.h>
|
#include <core/exception.h>
|
||||||
#include <notebook/node.h>
|
#include <notebook/node.h>
|
||||||
#include <notebook/notebook.h>
|
#include <notebook/notebook.h>
|
||||||
|
#include <utils/asyncworker.h>
|
||||||
|
|
||||||
#include "searchresultitem.h"
|
#include "searchresultitem.h"
|
||||||
#include "filesearchengine.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 logRequested(tr("Searching %n buffer(s)", "", p_buffers.size()));
|
||||||
|
|
||||||
emit progressUpdated(0, p_buffers.size());
|
m_firstPhaseWorker->doWork([this, p_buffers]() {
|
||||||
for (int i = 0; i < p_buffers.size(); ++i) {
|
emit progressUpdated(0, p_buffers.size());
|
||||||
if (!p_buffers[i]) {
|
for (int i = 0; i < p_buffers.size(); ++i) {
|
||||||
continue;
|
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()) {
|
emit finished(SearchState::Finished);
|
||||||
return SearchState::Stopped;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
auto file = p_buffers[i]->getFile();
|
return SearchState::Busy;
|
||||||
if (!firstPhaseSearch(file.data())) {
|
|
||||||
return SearchState::Failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit progressUpdated(i + 1, p_buffers.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
return SearchState::Finished;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchState Searcher::search(const QSharedPointer<SearchOption> &p_option, Node *p_folder)
|
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()));
|
emit logRequested(tr("Searching folder (%1)").arg(p_folder->getName()));
|
||||||
|
|
||||||
QVector<SearchSecondPhaseItem> secondPhaseItems;
|
m_firstPhaseWorker->doWork([this, p_folder]() {
|
||||||
if (!firstPhaseSearchFolder(p_folder, secondPhaseItems)) {
|
if (!firstPhaseSearchFolder(p_folder, m_secondPhaseItems)) {
|
||||||
return SearchState::Failed;
|
m_secondPhaseItems.clear();
|
||||||
}
|
emit finished(SearchState::Failed);
|
||||||
|
return;
|
||||||
if (isAskedToStop()) {
|
|
||||||
return SearchState::Stopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!secondPhaseItems.isEmpty()) {
|
|
||||||
// Do second phase search.
|
|
||||||
if (!secondPhaseSearch(secondPhaseItems)) {
|
|
||||||
return SearchState::Failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAskedToStop()) {
|
if (m_secondPhaseItems.isEmpty()) {
|
||||||
return SearchState::Stopped;
|
emit finished(SearchState::Finished);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return SearchState::Busy;
|
return SearchState::Busy;
|
||||||
}
|
|
||||||
|
|
||||||
return SearchState::Finished;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchState Searcher::search(const QSharedPointer<SearchOption> &p_option, const QVector<Notebook *> &p_notebooks)
|
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;
|
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());
|
emit logRequested(tr("Searching notebook (%1)").arg(p_notebooks[i]->getName()));
|
||||||
for (int i = 0; i < p_notebooks.size(); ++i) {
|
|
||||||
if (isAskedToStop()) {
|
if (!firstPhaseSearch(p_notebooks[i], m_secondPhaseItems)) {
|
||||||
return SearchState::Stopped;
|
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 (m_secondPhaseItems.isEmpty()) {
|
||||||
|
emit finished(SearchState::Finished);
|
||||||
if (!firstPhaseSearch(p_notebooks[i], secondPhaseItems)) {
|
|
||||||
return SearchState::Failed;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
emit progressUpdated(i + 1, p_notebooks.size());
|
return SearchState::Busy;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Searcher::prepare(const QSharedPointer<SearchOption> &p_option)
|
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);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Searcher::isAskedToStop() const
|
bool Searcher::isAskedToStop() const
|
||||||
{
|
{
|
||||||
QCoreApplication::sendPostedEvents();
|
|
||||||
return m_askedToStop;
|
return m_askedToStop;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,7 +357,7 @@ bool Searcher::firstPhaseSearchFolder(Node *p_node, QVector<SearchSecondPhaseIte
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (testTarget(SearchTarget::SearchFolder)) {
|
if (testTarget(SearchTarget::SearchFolder) && !p_node->isRoot()) {
|
||||||
const auto name = p_node->getName();
|
const auto name = p_node->getName();
|
||||||
const auto folderPath = p_node->fetchAbsolutePath();
|
const auto folderPath = p_node->fetchAbsolutePath();
|
||||||
const auto relativePath = p_node->fetchPath();
|
const auto relativePath = p_node->fetchPath();
|
||||||
@ -531,3 +531,26 @@ bool Searcher::searchTag(const Node *p_node) const
|
|||||||
|
|
||||||
return false;
|
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 <QSharedPointer>
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
#include "searchdata.h"
|
#include "searchdata.h"
|
||||||
#include "searchtoken.h"
|
#include "searchtoken.h"
|
||||||
@ -17,6 +18,7 @@ namespace vnotex
|
|||||||
struct SearchResultItem;
|
struct SearchResultItem;
|
||||||
class Node;
|
class Node;
|
||||||
class Notebook;
|
class Notebook;
|
||||||
|
class AsyncWorkerWithFunctor;
|
||||||
|
|
||||||
class Searcher : public QObject
|
class Searcher : public QObject
|
||||||
{
|
{
|
||||||
@ -83,6 +85,9 @@ namespace vnotex
|
|||||||
|
|
||||||
void createSearchEngine();
|
void createSearchEngine();
|
||||||
|
|
||||||
|
// Will be called after m_firstPhaseWorker finished.
|
||||||
|
void doSecondPhaseSearch();
|
||||||
|
|
||||||
QSharedPointer<SearchOption> m_option;
|
QSharedPointer<SearchOption> m_option;
|
||||||
|
|
||||||
SearchToken m_token;
|
SearchToken m_token;
|
||||||
@ -92,6 +97,11 @@ namespace vnotex
|
|||||||
bool m_askedToStop = false;
|
bool m_askedToStop = false;
|
||||||
|
|
||||||
QScopedPointer<ISearchEngine> m_engine;
|
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
|
QT += widgets svg
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
$$PWD/asyncworker.cpp \
|
||||||
$$PWD/callbackpool.cpp \
|
$$PWD/callbackpool.cpp \
|
||||||
$$PWD/contentmediautils.cpp \
|
$$PWD/contentmediautils.cpp \
|
||||||
$$PWD/docsutils.cpp \
|
$$PWD/docsutils.cpp \
|
||||||
@ -18,6 +19,7 @@ SOURCES += \
|
|||||||
$$PWD/clipboardutils.cpp
|
$$PWD/clipboardutils.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
$$PWD/asyncworker.h \
|
||||||
$$PWD/callbackpool.h \
|
$$PWD/callbackpool.h \
|
||||||
$$PWD/contentmediautils.h \
|
$$PWD/contentmediautils.h \
|
||||||
$$PWD/docsutils.h \
|
$$PWD/docsutils.h \
|
||||||
|
@ -40,6 +40,10 @@ SearchPanel::SearchPanel(const QSharedPointer<ISearchInfoProvider> &p_provider,
|
|||||||
{
|
{
|
||||||
qRegisterMetaType<QVector<QSharedPointer<SearchResultItem>>>("QVector<QSharedPointer<SearchResultItem>>");
|
qRegisterMetaType<QVector<QSharedPointer<SearchResultItem>>>("QVector<QSharedPointer<SearchResultItem>>");
|
||||||
|
|
||||||
|
qRegisterMetaType<QSharedPointer<SearchResultItem>>("QSharedPointer<SearchResultItem>");
|
||||||
|
|
||||||
|
qRegisterMetaType<SearchState>("SearchState");
|
||||||
|
|
||||||
setupUI();
|
setupUI();
|
||||||
|
|
||||||
initOptions();
|
initOptions();
|
||||||
@ -442,9 +446,6 @@ SearchState SearchPanel::search(const QSharedPointer<SearchOption> &p_option)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
auto folder = m_provider->getCurrentFolder();
|
auto folder = m_provider->getCurrentFolder();
|
||||||
if (folder && (folder->isRoot())) {
|
|
||||||
folder = nullptr;
|
|
||||||
}
|
|
||||||
if (!folder) {
|
if (!folder) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user