mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
PERF: Make mega topics work without a stream.
There are tradeoffs that we took here. For the complete story see https://meta.discourse.org/t/performance-improvements-on-long-topics/30187/27?u=tgxworld.
This commit is contained in:
@@ -4,6 +4,7 @@ require_dependency 'filter_best_posts'
|
||||
require_dependency 'gaps'
|
||||
|
||||
class TopicView
|
||||
MEGA_TOPIC_POSTS_COUNT = 25
|
||||
|
||||
attr_reader :topic, :posts, :guardian, :filtered_posts, :chunk_size, :print, :message_bus_last_id
|
||||
attr_accessor :draft, :draft_key, :draft_sequence, :user_custom_fields, :post_custom_fields, :post_number
|
||||
@@ -51,7 +52,6 @@ class TopicView
|
||||
self.instance_variable_set("@#{key}".to_sym, value)
|
||||
end
|
||||
|
||||
@_post_number = @post_number.dup
|
||||
@post_number = [@post_number.to_i, 1].max
|
||||
@page = [@page.to_i, 1].max
|
||||
|
||||
@@ -209,6 +209,11 @@ class TopicView
|
||||
def filter_posts(opts = {})
|
||||
return filter_posts_near(opts[:post_number].to_i) if opts[:post_number].present?
|
||||
return filter_posts_by_ids(opts[:post_ids]) if opts[:post_ids].present?
|
||||
|
||||
if opts[:filter_post_number].present?
|
||||
return filter_posts_by_post_number(opts[:filter_post_number], opts[:asc])
|
||||
end
|
||||
|
||||
return filter_best(opts[:best], opts) if opts[:best].present?
|
||||
|
||||
filter_posts_paged(@page)
|
||||
@@ -244,29 +249,19 @@ class TopicView
|
||||
posts_before = (@limit.to_f / 4).floor
|
||||
posts_before = 1 if posts_before.zero?
|
||||
|
||||
sort_order_sql = <<~SQL
|
||||
(
|
||||
SELECT posts.sort_order
|
||||
FROM posts
|
||||
WHERE posts.post_number = #{post_number.to_i}
|
||||
AND posts.topic_id = #{@topic.id.to_i}
|
||||
LIMIT 1
|
||||
)
|
||||
SQL
|
||||
|
||||
before_post_ids = @filtered_posts.order(sort_order: :desc)
|
||||
.where("posts.sort_order < #{sort_order_sql}",)
|
||||
.where("posts.sort_order < #{sort_order_sql(post_number)}",)
|
||||
.limit(posts_before)
|
||||
.pluck(:id)
|
||||
|
||||
post_ids = before_post_ids + @filtered_posts.order(sort_order: :asc)
|
||||
.where("posts.sort_order >= #{sort_order_sql}")
|
||||
.where("posts.sort_order >= #{sort_order_sql(post_number)}")
|
||||
.limit(@limit - before_post_ids.length)
|
||||
.pluck(:id)
|
||||
|
||||
if post_ids.length < @limit
|
||||
post_ids = post_ids + @filtered_posts.order(sort_order: :desc)
|
||||
.where("posts.sort_order < #{sort_order_sql}")
|
||||
.where("posts.sort_order < #{sort_order_sql(post_number)}")
|
||||
.offset(before_post_ids.length)
|
||||
.limit(@limit - post_ids.length)
|
||||
.pluck(:id)
|
||||
@@ -456,6 +451,18 @@ class TopicView
|
||||
@filtered_posts.where(post_number: post_number).pluck(:id).first
|
||||
end
|
||||
|
||||
def is_mega_topic?
|
||||
@is_mega_topic ||= (@topic.posts_count >= MEGA_TOPIC_POSTS_COUNT)
|
||||
end
|
||||
|
||||
def first_post_id
|
||||
@filtered_posts.order(sort_order: :asc).limit(1).pluck(:id).first
|
||||
end
|
||||
|
||||
def last_post_id
|
||||
@filtered_posts.order(sort_order: :desc).limit(1).pluck(:id).first
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def read_posts_set
|
||||
@@ -476,6 +483,18 @@ class TopicView
|
||||
|
||||
private
|
||||
|
||||
def sort_order_sql(post_number)
|
||||
<<~SQL
|
||||
(
|
||||
SELECT posts.sort_order
|
||||
FROM posts
|
||||
WHERE posts.post_number = #{post_number.to_i}
|
||||
AND posts.topic_id = #{@topic.id.to_i}
|
||||
LIMIT 1
|
||||
)
|
||||
SQL
|
||||
end
|
||||
|
||||
def filter_post_types(posts)
|
||||
visible_types = Topic.visible_post_types(@user)
|
||||
|
||||
@@ -486,6 +505,24 @@ class TopicView
|
||||
end
|
||||
end
|
||||
|
||||
def filter_posts_by_post_number(post_number, asc)
|
||||
posts =
|
||||
if asc
|
||||
@filtered_posts
|
||||
.where("sort_order > #{sort_order_sql(post_number)}")
|
||||
.order(sort_order: :asc)
|
||||
else
|
||||
@filtered_posts
|
||||
.where("sort_order < #{sort_order_sql(post_number)}")
|
||||
.order(sort_order: :desc)
|
||||
end
|
||||
|
||||
posts = posts.limit(@limit)
|
||||
filter_posts_by_ids(posts.pluck(:id))
|
||||
|
||||
@posts = @posts.unscope(:order).order(sort_order: :desc) if !asc
|
||||
end
|
||||
|
||||
def filter_posts_by_ids(post_ids)
|
||||
# TODO: Sort might be off
|
||||
@posts = Post.where(id: post_ids, topic_id: @topic.id)
|
||||
@@ -573,10 +610,4 @@ class TopicView
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
MEGA_TOPIC_POSTS_COUNT = 10000
|
||||
|
||||
def is_mega_topic?
|
||||
@is_mega_topic ||= (@topic.posts_count >= MEGA_TOPIC_POSTS_COUNT)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user