#pragma once #include "search/search_params.hpp" #include "search/suggest.hpp" #include "indexer/categories_holder.hpp" #include "base/macros.hpp" #include "base/thread.hpp" #include <condition_variable> #include <functional> #include <memory> #include <mutex> #include <queue> #include <string> #include <vector> class DataSource; namespace storage { class CountryInfoGetter; } namespace search { class EngineData; class Processor; // This class is used as a reference to a search processor in the // SearchEngine's queue. It's only possible to cancel a search // request via this reference. // // NOTE: this class is thread-safe. class ProcessorHandle { public: ProcessorHandle(); // Cancels processor this handle points to. void Cancel(); private: friend class Engine; // Attaches the handle to a |processor|. If there was or will be a // cancel signal, this signal will be propagated to |processor|. // This method is called only once, when search engine starts // the processor this handle corresponds to. void Attach(Processor & processor); // Detaches handle from a processor. This method is called only // once, when search engine completes processing of the query // that this handle corresponds to. void Detach(); Processor * m_processor; bool m_cancelled; std::mutex m_mu; DISALLOW_COPY_AND_MOVE(ProcessorHandle); }; // This class is a wrapper around thread which processes search // queries one by one. // // NOTE: this class is thread safe. class Engine { public: struct Params { Params(); Params(std::string const & locale, size_t numThreads); std::string m_locale; // This field controls number of threads SearchEngine will create // to process queries. Use this field wisely as large values may // negatively affect performance due to false sharing. size_t m_numThreads; }; // Doesn't take ownership of dataSource and categories. Engine(DataSource & dataSource, CategoriesHolder const & categories, storage::CountryInfoGetter const & infoGetter, Params const & params); ~Engine(); // Posts search request to the queue and returns its handle. std::weak_ptr<ProcessorHandle> Search(SearchParams params); // Sets default locale on all query processors. void SetLocale(std::string const & locale); // Returns the number of request-processing threads. size_t GetNumThreads() const; // Posts request to clear caches to the queue. void ClearCaches(); // Posts requests to load and cache localities from World.mwm. void CacheWorldLocalities(); // Posts request to reload cities boundaries tables. void LoadCitiesBoundaries(); // Posts request to load countries tree. void LoadCountriesTree(); void EnableIndexingOfBookmarksDescriptions(bool enable); void EnableIndexingOfBookmarkGroup(bookmarks::GroupId const & groupId, bool enable); // Clears all bookmarks data and caches for all processors. void ResetBookmarks(); void OnBookmarksCreated(std::vector<std::pair<bookmarks::Id, bookmarks::Doc>> const & marks); void OnBookmarksUpdated(std::vector<std::pair<bookmarks::Id, bookmarks::Doc>> const & marks); void OnBookmarksDeleted(std::vector<bookmarks::Id> const & marks); void OnBookmarksAttachedToGroup(bookmarks::GroupId const & groupId, std::vector<bookmarks::Id> const & marks); void OnBookmarksDetachedFromGroup(bookmarks::GroupId const & groupId, std::vector<bookmarks::Id> const & marks); private: struct Message { using Fn = std::function<void(Processor & processor)>; enum Type { TYPE_TASK, TYPE_BROADCAST }; template <typename Gn> Message(Type type, Gn && gn) : m_type(type), m_fn(std::forward<Gn>(gn)) {} void operator()(Processor & processor) { m_fn(processor); } Type m_type; Fn m_fn; }; struct Context { // This field *CAN* be accessed by other threads, so |m_mu| must // be taken before access this queue. Messages are ordered here // by a timestamp and all timestamps are less than timestamps in // the global |m_messages| queue. std::queue<Message> m_messages; // This field is thread-specific and *CAN NOT* be accessed by // other threads. std::unique_ptr<Processor> m_processor; }; // *ALL* following methods are executed on the m_threads threads. // This method executes tasks from a common pool (|tasks|) in a FIFO // manner. |broadcast| contains per-thread tasks, but nevertheless // all necessary synchronization primitives must be used to access // |tasks| and |broadcast|. void MainLoop(Context & context); template <typename... Args> void PostMessage(Args &&... args); void DoSearch(SearchParams params, std::shared_ptr<ProcessorHandle> handle, Processor & processor); std::vector<Suggest> m_suggests; bool m_shutdown; std::mutex m_mu; std::condition_variable m_cv; std::queue<Message> m_messages; std::vector<Context> m_contexts; std::vector<threads::SimpleThread> m_threads; }; } // namespace search