-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move status counters to separate table, count replies #8104
Conversation
a5b256b
to
75fae7b
Compare
app/models/favourite.rb
Outdated
else | ||
Status.where(id: status_id).update_all('favourites_count = COALESCE(favourites_count, 0) + 1') | ||
StatusStat.where(status_id: status_id).update_all('favourites_count = COALESCE(favourites_count, 0) + 1') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Crap, just realized the record may not exist when this is executed. Hmm.
87a1fbc
to
a508cb5
Compare
3e3c145
to
85e5448
Compare
I don't believe the I'd suggest adding a trigger to update these stats, though, along the lines of https://github.com/tootsuite/mastodon/blob/master/lib/mastodon/migration_helpers.rb#L698 . (Otherwise, any changes between this migration being started and the code being rolled out will be omitted.) Even with that trigger, the ON CONFLICT DO UPDATE will overwrite any values that change during the migration, although I'm not sure there's a much better way to do it. (You could take the old value if the overwriting value would be zero, which is probably more right more of the time, but there's no good way without making the migration significantly more complicated. A sketch on how to do that is below if you want it.) Other than that race, this looks fine. I'm not sure if you really need timestamps on StatusStat, but other than doubling the amount of space used for status timestamps, it's not really hurting anything (and could possibly be useful, since the update timestamp on Status won't catch these changing any longer). You'll need another migration to backfill reply counts, but I assume you know that. If you really want to not lose updated counts during that migration, one option would be to:
(In theory, you'll want to do the same when filling in the replies_count, but that query will probably take a while, and you'll want the trigger to not just increment/decrement the count, but to calculate it correctly each time, because there's no "correct" value to reference.) |
@aschmitz Thank you for the assessment! I feel more confident about this update now. As for counter accuracy, I think it is negligible (some super old posts have negative counters due to the first ever migration close to two years ago). For example, remote posts only count local favourites/reblogs anyway, so we're not losing correctness because we don't have any. |
class CreateStatusStats < ActiveRecord::Migration[5.2] | ||
def change | ||
create_table :status_stats do |t| | ||
t.belongs_to :status, foreign_key: { on_delete: :cascade }, index: { unique: true } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that it is better to set null: false
. Also, it seems that foreign_key is not reflected in db/schema.rb
.
@@ -26,6 +24,8 @@ | |||
# | |||
|
|||
class Status < ApplicationRecord | |||
self.cache_versioning = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be better to stop changing cache_versioning and stop using cache_key directly.
def change | ||
safety_assured do | ||
remove_column :statuses, :reblogs_count, :integer, default: 0, null: false | ||
remove_column :statuses, :favourites_count, :integer, default: 0, null: false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These will cause any existing uses of these columns to throw errors until the running code is also reloaded: I might suggest waiting on this for a later release, so most people won't have old code running when these columns are removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aschmitz It's a two-step migration, see OP
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, right-o. Didn't realize that had changed. (Or that this was in post_migrate
.) Carry on, then!
59748dd
to
83203bf
Compare
@abcang Fixed |
* Move status counters to separate table, count replies * Migration to remove old counter columns from statuses table * Fix schema file
See #7908 for separate table justification
Also, Rails 5.2 had a breaking change in
cache_key
behaviour, which removed the updated_at timestamp from the key! Therefore, the cache was always stale.cache_version = false
restores old behaviour we were expecting...The data from statuses table is copied in a migration using UPSERT mechanics introduced in Postgres 9.5 to avoid conflicts.
Instructions:
SKIP_POST_DEPLOYMENT_MIGRATIONS=true rails db:migrate
firstrails db:migrate
See also: Showing replies_count in web UI (#8181)