From 526332c5454b67f1c498dc82e71657258a79d7e9 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Wed, 2 Jun 2021 17:41:25 +0200
Subject: [PATCH] Fix account deletion sometimes failing because of optimistic
 locks (#16317)

* Fix account deletion sometimes failing because of optimistic locks

In some rare occasions[1], deleting accounts would fail with a
`StaleObjectError` exception.

Indeed, account deletion manually sets the `AccountStat` values without
handling cases where the optimistic locking on `AccountStat` would fail.

To my knowledge, with the rewrite of account counters in #15913, the
`DeleteAccountService` is now the only place that changes the counters in
a way that is not atomic.

Since in this specific case, we do not care about the previous values of the
account counters, it appears we don't need locking at all for this table
anymore.

[1]: https://discourse.joinmastodon.org/t/account-cant-be-deleted/3602

* Bump MAX_SUPPORTED_VERSION in maintenance script
---
 app/models/account_stat.rb                               | 3 ++-
 app/models/concerns/account_counters.rb                  | 2 --
 ...10526193025_remove_lock_version_from_account_stats.rb | 9 +++++++++
 db/schema.rb                                             | 3 +--
 lib/mastodon/maintenance_cli.rb                          | 2 +-
 5 files changed, 13 insertions(+), 6 deletions(-)
 create mode 100644 db/post_migrate/20210526193025_remove_lock_version_from_account_stats.rb

diff --git a/app/models/account_stat.rb b/app/models/account_stat.rb
index a826a9af3b..44da4f0d00 100644
--- a/app/models/account_stat.rb
+++ b/app/models/account_stat.rb
@@ -11,10 +11,11 @@
 #  created_at      :datetime         not null
 #  updated_at      :datetime         not null
 #  last_status_at  :datetime
-#  lock_version    :integer          default(0), not null
 #
 
 class AccountStat < ApplicationRecord
+  self.locking_column = nil
+
   belongs_to :account, inverse_of: :account_stat
 
   update_index('accounts#account', :account)
diff --git a/app/models/concerns/account_counters.rb b/app/models/concerns/account_counters.rb
index fd3f161ad5..3fabb52054 100644
--- a/app/models/concerns/account_counters.rb
+++ b/app/models/concerns/account_counters.rb
@@ -49,7 +49,6 @@ module AccountCounters
               ON CONFLICT (account_id) DO UPDATE
               SET #{key} = account_stats.#{key} + :value,
                   last_status_at = now(),
-                  lock_version = account_stats.lock_version + 1,
                   updated_at = now()
               RETURNING id;
             SQL
@@ -59,7 +58,6 @@ module AccountCounters
                 VALUES (:account_id, :default_value, now(), now())
               ON CONFLICT (account_id) DO UPDATE
               SET #{key} = account_stats.#{key} + :value,
-                  lock_version = account_stats.lock_version + 1,
                   updated_at = now()
               RETURNING id;
             SQL
diff --git a/db/post_migrate/20210526193025_remove_lock_version_from_account_stats.rb b/db/post_migrate/20210526193025_remove_lock_version_from_account_stats.rb
new file mode 100644
index 0000000000..3079bed09c
--- /dev/null
+++ b/db/post_migrate/20210526193025_remove_lock_version_from_account_stats.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class RemoveLockVersionFromAccountStats < ActiveRecord::Migration[5.2]
+  def change
+    safety_assured do
+      remove_column :account_stats, :lock_version, :integer, null: false, default: 0
+    end
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 583bdf317d..3fcee2d304 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 2021_05_07_001928) do
+ActiveRecord::Schema.define(version: 2021_05_26_193025) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -111,7 +111,6 @@ ActiveRecord::Schema.define(version: 2021_05_07_001928) do
     t.datetime "created_at", null: false
     t.datetime "updated_at", null: false
     t.datetime "last_status_at"
-    t.integer "lock_version", default: 0, null: false
     t.index ["account_id"], name: "index_account_stats_on_account_id", unique: true
   end
 
diff --git a/lib/mastodon/maintenance_cli.rb b/lib/mastodon/maintenance_cli.rb
index 8e2084e335..47e2d78bb1 100644
--- a/lib/mastodon/maintenance_cli.rb
+++ b/lib/mastodon/maintenance_cli.rb
@@ -14,7 +14,7 @@ module Mastodon
     end
 
     MIN_SUPPORTED_VERSION = 2019_10_01_213028
-    MAX_SUPPORTED_VERSION = 2021_05_07_001928
+    MAX_SUPPORTED_VERSION = 2021_05_26_193025
 
     # Stubs to enjoy ActiveRecord queries while not depending on a particular
     # version of the code/database
-- 
GitLab