diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2014-12-20 09:33:02 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2014-12-20 09:33:02 +0000 |
commit | 717f491f503d214b639f5b98e497e4189fc34902 (patch) | |
tree | 9fcf57ecc6ef31fd43c03b294906b036c03aa285 | |
parent | 71172e241169933bbec364afe9268b4b36d9045f (diff) | |
download | redmine-717f491f503d214b639f5b98e497e4189fc34902.tar.gz redmine-717f491f503d214b639f5b98e497e4189fc34902.zip |
Cache search result ids for faster search pagination (#18631).
git-svn-id: http://svn.redmine.org/redmine/trunk@13770 e93f8b46-1217-0410-a6f0-8f06a7374b81
-rw-r--r-- | app/controllers/search_controller.rb | 4 | ||||
-rw-r--r-- | config/application.rb | 8 | ||||
-rw-r--r-- | lib/redmine/search.rb | 38 |
3 files changed, 46 insertions, 4 deletions
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index ac52f42b6..3f80b18b0 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -18,8 +18,6 @@ class SearchController < ApplicationController before_filter :find_optional_project - @@search_cache_store ||= ActiveSupport::Cache.lookup_store :memory_store - def index @question = params[:q] || "" @question.strip! @@ -57,7 +55,7 @@ class SearchController < ApplicationController fetcher = Redmine::Search::Fetcher.new( @question, User.current, @scope, projects_to_search, - :all_words => @all_words, :titles_only => @titles_only + :all_words => @all_words, :titles_only => @titles_only, :cache => params[:page].present? ) if fetcher.tokens.present? diff --git a/config/application.rb b/config/application.rb index b05c5287e..a2918a65c 100644 --- a/config/application.rb +++ b/config/application.rb @@ -47,6 +47,14 @@ module RedmineApp # Do not include all helpers config.action_controller.include_all_helpers = false + # Specific cache for search results, the default file store cache is not + # a good option as it could grow fast. A memory store (32MB max) is used + # as the default. If you're running multiple server processes, it's + # recommended to switch to a shared cache store (eg. mem_cache_store). + # See http://guides.rubyonrails.org/caching_with_rails.html#cache-stores + # for more options (same options as config.cache_store). + config.redmine_search_cache_store = :memory_store + config.session_store :cookie_store, :key => '_redmine_session' if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb')) diff --git a/lib/redmine/search.rb b/lib/redmine/search.rb index 42d3004b2..da1d5c6f6 100644 --- a/lib/redmine/search.rb +++ b/lib/redmine/search.rb @@ -31,6 +31,18 @@ module Redmine search_type = search_type.to_s @@available_search_types << search_type unless @@available_search_types.include?(search_type) end + + # Returns the cache store for search results + # Can be configured with config.redmine_search_cache_store= in config/application.rb + def cache_store + @@cache_store ||= begin + # if config.search_cache_store was not previously set, a no method error would be raised + config = Rails.application.config.redmine_search_cache_store rescue :memory_store + if config + ActiveSupport::Cache.lookup_store config + end + end + end end class Fetcher @@ -41,6 +53,7 @@ module Redmine @question = question.strip @scope = scope @projects = projects + @cache = options.delete(:cache) @options = options # extract tokens from the question @@ -52,10 +65,12 @@ module Redmine @tokens.slice! 5..-1 end + # Returns the total result count def result_count result_ids.size end + # Returns the result count by type def result_count_by_type ret = Hash.new {|h,k| h[k] = 0} result_ids.group_by(&:first).each do |scope, ids| @@ -64,6 +79,7 @@ module Redmine ret end + # Returns the results for the given offset and limit def results(offset, limit) result_ids_to_load = result_ids[offset, limit] || [] @@ -78,12 +94,31 @@ module Redmine end.compact end + # Returns the results ids, sorted by rank def result_ids - @ranks_and_ids ||= load_result_ids + @ranks_and_ids ||= load_result_ids_from_cache end private + def project_ids + Array.wrap(@projects).map(&:id) + end + + def load_result_ids_from_cache + if Redmine::Search.cache_store + cache_key = ActiveSupport::Cache.expand_cache_key( + [@question, @user.id, @scope.sort, @options, project_ids.sort] + ) + + Redmine::Search.cache_store.fetch(cache_key, :force => !@cache) do + load_result_ids + end + else + load_result_ids + end + end + def load_result_ids ret = [] # get all the results ranks and ids @@ -95,6 +130,7 @@ module Redmine end # sort results, higher rank and id first ret.sort! {|a,b| b.last <=> a.last} + # only keep ids now that results are sorted ret.map! {|scope, r| [scope, r.last]} ret end |