Skip to content

Instantly share code, notes, and snippets.

@crakaC
Last active August 17, 2019 13:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crakaC/029df466faed06aef9076714999937b7 to your computer and use it in GitHub Desktop.
Save crakaC/029df466faed06aef9076714999937b7 to your computer and use it in GitHub Desktop.
MastodonのDBサイズが膨らんできたので不要っぽいレコードを削除した

MastodonのDBメンテという名のレコード削除祭り

tootctl statuses remove

ローカルユーザーにとって不要なトゥートを削除するジョブ。
そのままだと思いの外うまく消えてくれないのでいくつか変更&修正。

diff --git a/lib/mastodon/statuses_cli.rb b/lib/mastodon/statuses_cli.rb
index 7f2fbfa85..5c7c877fb 100644
--- a/lib/mastodon/statuses_cli.rb
+++ b/lib/mastodon/statuses_cli.rb
@@ -36,16 +36,17 @@ module Mastodon
 
       Status.remote
             .where('id < ?', max_id)
-            .where(reblog_of_id: nil)                                                                                                                                                                                              # Skip reblogs
-            .where(in_reply_to_id: nil)                                                                                                                                                                                            # Skip replies
             .where('id NOT IN (SELECT status_pins.status_id FROM status_pins WHERE statuses.id = status_id)')                                                                                                                      # Skip statuses that are pinned on profiles
             .where('id NOT IN (SELECT mentions.status_id FROM mentions WHERE statuses.id = mentions.status_id AND mentions.account_id IN (SELECT accounts.id FROM accounts WHERE domain IS NULL))')                                # Skip statuses that mention local accounts
-            .where('id NOT IN (SELECT statuses1.in_reply_to_id FROM statuses AS statuses1 WHERE statuses.id = statuses1.in_reply_to_id)')                                                                                          # Skip statuses favourited by local accounts
+            .where('id NOT IN (SELECT statuses1.in_reply_to_id FROM statuses AS statuses1 WHERE statuses.id = statuses1.in_reply_to_id AND statuses1.account_id IN (SELECT accounts.id FROM accounts WHERE accounts.domain IS NULL))') # Skip statuses replyed by local accounts
+            .where('id NOT IN (SELECT favourites.status_id FROM favourites WHERE statuses.id = favourites.status_id AND favourites.account_id IN (SELECT accounts.id FROM accounts WHERE domain IS NULL))')                        # Skip statuses favourited by local accounts
             .where('id NOT IN (SELECT statuses1.reblog_of_id FROM statuses AS statuses1 WHERE statuses.id = statuses1.reblog_of_id AND statuses1.account_id IN (SELECT accounts.id FROM accounts WHERE accounts.domain IS NULL))') # Skip statuses reblogged by local accounts
-            .where('account_id NOT IN (SELECT follows.target_account_id FROM follows WHERE statuses.account_id = follows.target_account_id)')                                                                                      # Skip accounts followed by local accounts
+            .where('account_id NOT IN (SELECT accounts.id FROM accounts WHERE accounts.domain IS NULL)')                                                                                                                           # Skip local accounts
             .in_batches
             .delete_all
 
+      Conversation.where('id NOT IN (SELECT conversation_id from statuses)').in_batches.delete_all # Remove conversations
+
       say('Beginning removal of now-orphaned media attachments to free up disk space...')
 
       Scheduler::MediaCleanupScheduler.new.perform

ブースト、リプライは除外されてますがまあ別にいいだろうということで消します。

ローカルユーザーがお気に入りしたトゥートは省くというコメントがありますが実態はリプライ元のトゥートは消さないという処理になっています。
ローカルユーザーのリプライに対しての元トゥートさえ残っていればいいのでANDで条件を足しました。あと、コメント通りの処理を追加しました。

ローカルユーザがフォローしているリモートユーザのトゥートは削除しないようになっていますが、リモートユーザのトゥートは最悪外部に見に行けばいいよねってことでローカルのみ残します。

トゥートが消えてもconversationsが以外とでかいので、消し飛ばしたstatusesに紐付いているconversationsもついでに消します。

これでDBのサイズが2GBから200MBまで縮みました。やったね。

TODO

ほとんど関係のないドンブラコと流れ着いたアカウントがピン留めしているトゥート(約1万)を消したい。
というかドンブラコしてきたアカウントのアイコンやヘッダが微妙にS3に溜まってきていているのでなんかしたい。

追記

上記のようにしてトゥートを削除すると、リモートユーザ同士の会話にローカルユーザが混じっていた場合会話ツリーが完全に保存されない。
ローカルユーザが関連しているConversationを保持しようとするともっとしっかり条件を書いてやる必要がある。

同一conversation_idにローカルユーザのトゥートが含まれていないならば消せる感じだろうか?

Status.remote
    .where(`conversation_id NOT IN (SELECT id from conversations WHERE id IN (SELECT conversation_id FROM statuses WHERE statuses.account_id IN (SELECT id FROM accounts WHERE accounts.domain IS NULL)))`)

絶対もっと簡潔に書ける気がするがよくわからないのでとりあえずこんな感じかしら。(未検証)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment