Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-09-29 12:11:43 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-09-29 12:11:43 +0300
commitc724e639a91a4d112b7f0a05b3c6a0ffa6baa7a4 (patch)
treedccd51e5f480459820f1f908ad22584e8fe8689c /spec/support
parentcba55463a02fe6f9c9e8b6ed0b9ed38a0f087342 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/support')
-rw-r--r--spec/support/database_cleaner.rb27
-rw-r--r--spec/support/db_cleaner.rb75
2 files changed, 76 insertions, 26 deletions
diff --git a/spec/support/database_cleaner.rb b/spec/support/database_cleaner.rb
index b31881e3082..8f706fdebc9 100644
--- a/spec/support/database_cleaner.rb
+++ b/spec/support/database_cleaner.rb
@@ -17,32 +17,9 @@ RSpec.configure do |config|
delete_from_all_tables!(except: ['work_item_types'])
# Postgres maximum number of columns in a table is 1600 (https://github.com/postgres/postgres/blob/de41869b64d57160f58852eab20a27f248188135/src/include/access/htup_details.h#L23-L47).
- # And since:
- # "The DROP COLUMN form does not physically remove the column, but simply makes
- # it invisible to SQL operations. Subsequent insert and update operations in the
- # table will store a null value for the column. Thus, dropping a column is quick
- # but it will not immediately reduce the on-disk size of your table, as the space
- # occupied by the dropped column is not reclaimed.
- # The space will be reclaimed over time as existing rows are updated."
- # according to https://www.postgresql.org/docs/current/sql-altertable.html.
# We drop and recreate the database if any table has more than 1200 columns, just to be safe.
- max_allowed_columns = 1200
- tables_with_more_than_allowed_columns =
- ApplicationRecord.connection.execute("SELECT attrelid::regclass::text AS table, COUNT(*) AS column_count FROM pg_attribute GROUP BY attrelid HAVING COUNT(*) > #{max_allowed_columns}")
-
- if tables_with_more_than_allowed_columns.any?
- tables_with_more_than_allowed_columns.each do |result|
- puts "The #{result['table']} table has #{result['column_count']} columns."
- end
- puts "Recreating the database"
- start = Gitlab::Metrics::System.monotonic_time
-
- ActiveRecord::Tasks::DatabaseTasks.drop_current
- ActiveRecord::Tasks::DatabaseTasks.create_current
- ActiveRecord::Tasks::DatabaseTasks.load_schema_current
- ActiveRecord::Tasks::DatabaseTasks.migrate
-
- puts "Database re-creation done in #{Gitlab::Metrics::System.monotonic_time - start}"
+ if any_connection_class_with_more_than_allowed_columns?
+ recreate_all_databases!
end
end
diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb
index 940ff2751d3..316d645f99f 100644
--- a/spec/support/db_cleaner.rb
+++ b/spec/support/db_cleaner.rb
@@ -2,7 +2,7 @@
module DbCleaner
def all_connection_classes
- ::ActiveRecord::Base.connection_handler.connection_pool_names.map(&:constantize)
+ ::BeforeAllAdapter.all_connection_classes
end
def delete_from_all_tables!(except: [])
@@ -20,6 +20,79 @@ module DbCleaner
DatabaseCleaner[:active_record, { connection: connection_class }]
end
end
+
+ def any_connection_class_with_more_than_allowed_columns?
+ all_connection_classes.any? do |connection_class|
+ more_than_allowed_columns?(connection_class)
+ end
+ end
+
+ def more_than_allowed_columns?(connection_class)
+ # Postgres maximum number of columns in a table is 1600 (https://github.com/postgres/postgres/blob/de41869b64d57160f58852eab20a27f248188135/src/include/access/htup_details.h#L23-L47).
+ # And since:
+ # "The DROP COLUMN form does not physically remove the column, but simply makes
+ # it invisible to SQL operations. Subsequent insert and update operations in the
+ # table will store a null value for the column. Thus, dropping a column is quick
+ # but it will not immediately reduce the on-disk size of your table, as the space
+ # occupied by the dropped column is not reclaimed.
+ # The space will be reclaimed over time as existing rows are updated."
+ # according to https://www.postgresql.org/docs/current/sql-altertable.html.
+ # We drop and recreate the database if any table has more than 1200 columns, just to be safe.
+ max_allowed_columns = 1200
+ tables_with_more_than_allowed_columns = connection_class.connection.execute(<<-SQL)
+ SELECT attrelid::regclass::text AS table, COUNT(*) AS column_count
+ FROM pg_attribute
+ GROUP BY attrelid
+ HAVING COUNT(*) > #{max_allowed_columns}
+ SQL
+
+ tables_with_more_than_allowed_columns.each do |result|
+ puts "The #{result['table']} (#{connection_class.connection_db_config.name}) table has #{result['column_count']} columns."
+ end
+
+ tables_with_more_than_allowed_columns.any?
+ end
+
+ def recreate_all_databases!
+ start = Gitlab::Metrics::System.monotonic_time
+
+ puts "Recreating the database"
+
+ force_disconnect_all_connections!
+
+ ActiveRecord::Tasks::DatabaseTasks.drop_current
+ ActiveRecord::Tasks::DatabaseTasks.create_current
+ ActiveRecord::Tasks::DatabaseTasks.load_schema_current
+
+ # Migrate each database individually
+ with_reestablished_active_record_base do
+ all_connection_classes.each do |connection_class|
+ ActiveRecord::Base.establish_connection(connection_class.connection_db_config)
+
+ ActiveRecord::Tasks::DatabaseTasks.migrate
+ end
+ end
+
+ puts "Databases re-creation done in #{Gitlab::Metrics::System.monotonic_time - start}"
+ end
+
+ def force_disconnect_all_connections!
+ all_connection_classes.each do |connection_class|
+ # We use `connection_pool` to avoid going through
+ # Load Balancer since it does retry ops
+ pool = connection_class.connection_pool
+
+ # Force disconnect https://www.cybertec-postgresql.com/en/terminating-database-connections-in-postgresql/
+ pool.connection.execute(<<-SQL)
+ SELECT pg_terminate_backend(pid)
+ FROM pg_stat_activity
+ WHERE datname = #{pool.connection.quote(pool.db_config.database)}
+ AND pid != pg_backend_pid();
+ SQL
+
+ connection_class.connection_pool.disconnect!
+ end
+ end
end
DbCleaner.prepend_mod_with('DbCleaner')