#pragma once #include "search/bookmarks/processor.hpp" #include "search/search_params.hpp" #include "search/suggest.hpp" #include "indexer/categories_holder.hpp" #include "base/macros.hpp" #include "base/thread.hpp" #include #include #include #include #include #include #include #include #include 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 Search(SearchParams const & 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> const & marks); void OnBookmarksUpdated(std::vector> const & marks); void OnBookmarksDeleted(std::vector const & marks); void OnBookmarksAttachedToGroup(bookmarks::GroupId const & groupId, std::vector const & marks); void OnBookmarksDetachedFromGroup(bookmarks::GroupId const & groupId, std::vector const & marks); private: struct Message { using Fn = std::function; enum Type { TYPE_TASK, TYPE_BROADCAST }; template Message(Type type, Gn && gn) : m_type(type), m_fn(std::forward(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 m_messages; // This field is thread-specific and *CAN NOT* be accessed by // other threads. std::unique_ptr 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 void PostMessage(Args &&... args); void DoSearch(SearchParams const & params, std::shared_ptr handle, Processor & processor); std::vector m_suggests; bool m_shutdown; std::mutex m_mu; std::condition_variable m_cv; std::queue m_messages; std::vector m_contexts; std::vector m_threads; }; } // namespace search