aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThibG <thib@sitedethib.com>2020-09-07 18:00:15 +0200
committerGitHub <noreply@github.com>2020-09-07 18:00:15 +0200
commit517af45e32535efe1494c0e1e59304a5a7771dba (patch)
tree5862c7ec4ca28a09ba091e9c814cc9bc091d6b43
parente79d719e92e120ba3dd6ec2d8521f7aaa9482634 (diff)
downloadmastodon-517af45e32535efe1494c0e1e59304a5a7771dba.tar
mastodon-517af45e32535efe1494c0e1e59304a5a7771dba.tar.gz
mastodon-517af45e32535efe1494c0e1e59304a5a7771dba.tar.bz2
mastodon-517af45e32535efe1494c0e1e59304a5a7771dba.zip
Fix multiple boosts of a same toot erroneously appearing in TL (#14759)
* Check for and record reblog info atomically Instead of using ZREVRANK to determine whether a reblog is a new reblog or not, use ZADD's NX option to perform the check/addition option atomically. * Replace ZREVRANK call with ZSCORE key which is more efficient * Make tests a bit stricter * Fix off-by-one
-rw-r--r--app/lib/feed_manager.rb20
-rw-r--r--spec/lib/feed_manager_spec.rb4
2 files changed, 11 insertions, 13 deletions
diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb
index 9ab7b53be..785009b52 100644
--- a/app/lib/feed_manager.rb
+++ b/app/lib/feed_manager.rb
@@ -77,9 +77,11 @@ class FeedManager
# Get the score of the REBLOG_FALLOFF'th item in our feed, and stop
# tracking anything after it for deduplication purposes.
- falloff_rank = FeedManager::REBLOG_FALLOFF - 1
+ falloff_rank = FeedManager::REBLOG_FALLOFF
falloff_range = redis.zrevrange(timeline_key, falloff_rank, falloff_rank, with_scores: true)
- falloff_score = falloff_range&.first&.last&.to_i || 0
+ falloff_score = falloff_range&.first&.last&.to_i
+
+ return if falloff_score.nil?
# Get any reblogs we might have to clean up after.
redis.zrangebyscore(reblog_key, 0, falloff_score).each do |reblogged_id|
@@ -279,14 +281,12 @@ class FeedManager
return false if !rank.nil? && rank < FeedManager::REBLOG_FALLOFF
- reblog_rank = redis.zrevrank(reblog_key, status.reblog_of_id)
-
- if reblog_rank.nil?
+ # The ordered set at `reblog_key` holds statuses which have a reblog
+ # in the top `REBLOG_FALLOFF` statuses of the timeline
+ if redis.zadd(reblog_key, status.id, status.reblog_of_id, nx: true)
# This is not something we've already seen reblogged, so we
- # can just add it to the feed (and note that we're
- # reblogging it).
+ # can just add it to the feed (and note that we're reblogging it).
redis.zadd(timeline_key, status.id, status.id)
- redis.zadd(reblog_key, status.id, status.reblog_of_id)
else
# Another reblog of the same status was already in the
# REBLOG_FALLOFF most recent statuses, so we note that this
@@ -300,9 +300,7 @@ class FeedManager
# delay of the worker deliverying the original status, the late addition
# by merging timelines, and other reasons.
# If such a reblog already exists, just do not re-insert it into the feed.
- rank = redis.zrevrank(reblog_key, status.id)
-
- return false unless rank.nil?
+ return false unless redis.zscore(reblog_key, status.id).nil?
redis.zadd(timeline_key, status.id, status.id)
end
diff --git a/spec/lib/feed_manager_spec.rb b/spec/lib/feed_manager_spec.rb
index 5088d1742..d86dd7993 100644
--- a/spec/lib/feed_manager_spec.rb
+++ b/spec/lib/feed_manager_spec.rb
@@ -444,8 +444,8 @@ RSpec.describe FeedManager do
expect(Redis.current.exists?(reblog_set_key)).to be true
expect(Redis.current.zrange(reblogs_key, 0, -1)).to eq [reblogged.id.to_s]
- # Push everything off the end of the feed.
- FeedManager::MAX_ITEMS.times do
+ # Push everything past the reblog falloff.
+ FeedManager::REBLOG_FALLOFF.times do
FeedManager.instance.push_to_home(receiver, Fabricate(:status))
end