From 0b22e873c9844d3b3076c11ca4e28e602e0b055b Mon Sep 17 00:00:00 2001 From: evazion Date: Tue, 12 Oct 2021 00:41:00 -0500 Subject: [PATCH] search: cache timed out search counts. When a search is performed, we cache the post count so we don't have to calculate it again every time the user switches pages. However, if the count times out, we didn't cache it before, causing us to do a slow count on every page load. This usually happens on multi-tag searches that return a lot of results, `1girl solo` for example. This changes it so that the count is cached even when it times out. This will speed up large multi-tag searches. This also changes it so that the count is cached for a fixed 5 minutes. Before it was variable based on the size of the count, but this probably didn't make much difference. --- app/logical/post_query_builder.rb | 20 +++++++------------- test/unit/post_query_builder_test.rb | 11 +++-------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/app/logical/post_query_builder.rb b/app/logical/post_query_builder.rb index 2a7ce3227..72ffdf18e 100644 --- a/app/logical/post_query_builder.rb +++ b/app/logical/post_query_builder.rb @@ -902,8 +902,8 @@ class PostQueryBuilder def fast_count(timeout: 1_000, estimate_count: true, skip_cache: false) count = nil count = estimated_count if estimate_count - count = cached_count if count.nil? && !skip_cache - count = exact_count(timeout) if count.nil? + count = cached_count(timeout) if count.nil? && !skip_cache + count = exact_count(timeout) if count.nil? && skip_cache count end @@ -936,22 +936,16 @@ class PostQueryBuilder ExplainParser.new(build).row_count end - def cached_count - Cache.get(count_cache_key) + def cached_count(timeout, duration: 5.minutes) + Cache.get(count_cache_key, duration) do + exact_count(timeout) + end end def exact_count(timeout) - count = Post.with_timeout(timeout, nil) do + Post.with_timeout(timeout) do build.count end - - set_cached_count(count) if count.present? - count - end - - def set_cached_count(count) - expiry = count.seconds.clamp(3.minutes, 20.hours).to_i - Cache.put(count_cache_key, count, expiry) end def count_cache_key diff --git a/test/unit/post_query_builder_test.rb b/test/unit/post_query_builder_test.rb index f1355e67b..01a6afc87 100644 --- a/test/unit/post_query_builder_test.rb +++ b/test/unit/post_query_builder_test.rb @@ -1199,7 +1199,7 @@ class PostQueryBuilderTest < ActiveSupport::TestCase context "for a single metatag" do should "return the correct cached count" do build(:tag, name: "score:42", post_count: -100).save(validate: false) - PostQueryBuilder.new("score:42").set_cached_count(100) + Cache.put("pfc:score:42", 100) assert_fast_count(100, "score:42") end @@ -1207,7 +1207,7 @@ class PostQueryBuilderTest < ActiveSupport::TestCase pool = create(:pool, post_ids: [1, 2, 3]) build(:tag, name: "pool:#{pool.id}", post_count: -100).save(validate: false) - PostQueryBuilder.new("pool:1234").set_cached_count(100) + Cache.put("pfc:pool:1234", 100) assert_fast_count(3, "pool:#{pool.id}") assert_fast_count(3, "pool:#{pool.name}") @@ -1237,7 +1237,7 @@ class PostQueryBuilderTest < ActiveSupport::TestCase context "for a multi-tag search" do should "return the cached count, if it exists" do - PostQueryBuilder.new("score:42 aaa").set_cached_count(100) + Cache.put("pfc:score:42 aaa", 100) assert_fast_count(100, "aaa score:42") end @@ -1245,11 +1245,6 @@ class PostQueryBuilderTest < ActiveSupport::TestCase assert_fast_count(1, "aaa score:42") end - should "set the expiration time" do - Cache.expects(:put).with(PostQueryBuilder.new("score:42 aaa").count_cache_key, 1, 180) - assert_fast_count(1, "aaa score:42") - end - should "work with the hide_deleted_posts option turned on" do create(:post, tag_string: "aaa", score: 42, is_deleted: true) assert_fast_count(1, "aaa score:42", { hide_deleted_posts: true })