1242e57c27
* Add tootctl maintenance fix-duplicates This tool goes through the database to detect and fix duplicates. This operation is very slow and may cause data loss (of data that would be inaccessible without intervention because of the existing index corruptions). It tries its best to make sensible decisions, and asks the user in some cases. * Add warning message in db:migrate hook * Clear Rails cache after being done with database deduplication Avoids followers hash cache being incorrect, among other things
87 lines
3 KiB
Ruby
87 lines
3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative '../mastodon/snowflake'
|
|
|
|
def each_schema_load_environment
|
|
# If we're in development, also run this for the test environment.
|
|
# This is a somewhat hacky way to do this, so here's why:
|
|
# 1. We have to define this before we load the schema, or we won't
|
|
# have a timestamp_id function when we get to it in the schema.
|
|
# 2. db:setup calls db:schema:load_if_ruby, which calls
|
|
# db:schema:load, which we define above as having a prerequisite
|
|
# of this task.
|
|
# 3. db:schema:load ends up running
|
|
# ActiveRecord::Tasks::DatabaseTasks.load_schema_current, which
|
|
# calls a private method `each_current_configuration`, which
|
|
# explicitly also does the loading for the `test` environment
|
|
# if the current environment is `development`, so we end up
|
|
# needing to do the same, and we can't even use the same method
|
|
# to do it.
|
|
|
|
if Rails.env.development?
|
|
test_conf = ActiveRecord::Base.configurations['test']
|
|
|
|
if test_conf['database']&.present?
|
|
ActiveRecord::Base.establish_connection(:test)
|
|
yield
|
|
ActiveRecord::Base.establish_connection(Rails.env.to_sym)
|
|
end
|
|
end
|
|
|
|
yield
|
|
end
|
|
|
|
namespace :db do
|
|
namespace :migrate do
|
|
desc 'Setup the db or migrate depending on state of db'
|
|
task setup: :environment do
|
|
begin
|
|
if ActiveRecord::Migrator.current_version.zero?
|
|
Rake::Task['db:migrate'].invoke
|
|
Rake::Task['db:seed'].invoke
|
|
end
|
|
rescue ActiveRecord::NoDatabaseError
|
|
Rake::Task['db:setup'].invoke
|
|
else
|
|
Rake::Task['db:migrate'].invoke
|
|
end
|
|
end
|
|
end
|
|
|
|
task :post_migration_hook do
|
|
at_exit do
|
|
unless %w(C POSIX).include?(ActiveRecord::Base.connection.execute('SELECT datcollate FROM pg_database WHERE datname = current_database();').first['datcollate'])
|
|
Rails.logger.warn 'WARNING: Your database is using an unsafe collation setting, which might result in index corruption.'
|
|
Rails.logger.warn 'WARNING: See https://docs.joinmastodon.org/admin/troubleshooting/index-corruption/#am-i-affected'
|
|
end
|
|
end
|
|
end
|
|
|
|
Rake::Task['db:migrate'].enhance(['db:post_migration_hook'])
|
|
|
|
# Before we load the schema, define the timestamp_id function.
|
|
# Idiomatically, we might do this in a migration, but then it
|
|
# wouldn't end up in schema.rb, so we'd need to figure out a way to
|
|
# get it in before doing db:setup as well. This is simpler, and
|
|
# ensures it's always in place.
|
|
Rake::Task['db:schema:load'].enhance ['db:define_timestamp_id']
|
|
|
|
# After we load the schema, make sure we have sequences for each
|
|
# table using timestamp IDs.
|
|
Rake::Task['db:schema:load'].enhance do
|
|
Rake::Task['db:ensure_id_sequences_exist'].invoke
|
|
end
|
|
|
|
task :define_timestamp_id do
|
|
each_schema_load_environment do
|
|
Mastodon::Snowflake.define_timestamp_id
|
|
end
|
|
end
|
|
|
|
task :ensure_id_sequences_exist do
|
|
each_schema_load_environment do
|
|
Mastodon::Snowflake.ensure_id_sequences_exist
|
|
end
|
|
end
|
|
end
|