diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-29 12:11:43 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-29 12:11:43 +0300 |
commit | c724e639a91a4d112b7f0a05b3c6a0ffa6baa7a4 (patch) | |
tree | dccd51e5f480459820f1f908ad22584e8fe8689c /spec/support | |
parent | cba55463a02fe6f9c9e8b6ed0b9ed38a0f087342 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/support')
-rw-r--r-- | spec/support/database_cleaner.rb | 27 | ||||
-rw-r--r-- | spec/support/db_cleaner.rb | 75 |
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') |