Module: Gitlab::Database::AsyncIndexes::MigrationHelpers
- Includes:
- PartitionHelpers
- Included in:
- MigrationHelpers
- Defined in:
- lib/gitlab/database/async_indexes/migration_helpers.rb
Instance Method Summary collapse
- #async_index_creation_available? ⇒ Boolean
-
#prepare_async_index(table_name, column_name, **options) ⇒ Object
Prepares an index for asynchronous creation.
- #prepare_async_index_from_sql(definition) ⇒ Object
-
#prepare_async_index_removal(table_name, column_name, options = {}) ⇒ Object
Prepares an index for asynchronous destruction.
- #unprepare_async_index(table_name, column_name, **options) ⇒ Object
- #unprepare_async_index_by_name(table_name, index_name, **options) ⇒ Object
Methods included from PartitionHelpers
#partition?, #table_partitioned?
Instance Method Details
#async_index_creation_available? ⇒ Boolean
171 172 173 |
# File 'lib/gitlab/database/async_indexes/migration_helpers.rb', line 171 def async_index_creation_available? table_exists?(:postgres_async_indexes) end |
#prepare_async_index(table_name, column_name, **options) ⇒ Object
Prepares an index for asynchronous creation.
Stores the index information in the postgres_async_indexes table to be created later. The index will be always be created CONCURRENTLY, so that option does not need to be given. If an existing asynchronous definition exists with the same name, the existing entry will be updated with the new definition.
If the requested index has already been created, it is not stored in the table for asynchronous creation.
Note: The add_index_options is the same method Rails uses to generate the index creation statements. As such, we can pass index creation options to the method the same as we would standard index creation.
Example usage:
INITIAL_PIPELINE_INDEX = ‘tmp_index_vulnerability_occurrences_id_and_initial_pipline_id’ INITIAL_PIPELINE_COLUMNS = [:id, :initial_pipeline_id]
prepare_async_index TABLE_NAME, INITIAL_PIPELINE_COLUMNS, name: INITIAL_PIPELINE_INDEX, where: ‘initial_pipeline_id IS NULL’
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/gitlab/database/async_indexes/migration_helpers.rb', line 51 def prepare_async_index(table_name, column_name, **) Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode! if table_partitioned?(table_name) raise ArgumentError, 'prepare_async_index can not be used on a partitioned ' \ 'table. Please use prepare_partitioned_async_index on the partitioned table.' end if partition?(table_name) raise ArgumentError, 'prepare_async_index can not be used on a child partition ' \ 'table. Please use prepare_partitioned_async_index on the partitioned table.' end return unless async_index_creation_available? raise "Table #{table_name} does not exist" unless table_exists?(table_name) index_name = [:name] || index_name(table_name, column_name) raise 'Specifying index name is mandatory - specify name: argument' unless index_name = .merge({ algorithm: :concurrently }) if index_exists?(table_name, column_name, **) Gitlab::AppLogger.warn( message: 'Index not prepared because it already exists', table_name: table_name, index_name: index_name) return end index, algorithm, if_not_exists = (table_name, column_name, **) create_index = ActiveRecord::ConnectionAdapters::CreateIndexDefinition.new(index, algorithm, if_not_exists) schema_creation = ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaCreation.new(ApplicationRecord.connection) definition = schema_creation.accept(create_index) async_index = PostgresAsyncIndex.find_or_create_by!(name: index_name) do |rec| rec.table_name = table_name rec.definition = definition end async_index.definition = definition async_index.save! # No-op if definition is not changed Gitlab::AppLogger.info( message: 'Prepared index for async creation', table_name: async_index.table_name, index_name: async_index.name) async_index end |
#prepare_async_index_from_sql(definition) ⇒ Object
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/gitlab/database/async_indexes/migration_helpers.rb', line 104 def prepare_async_index_from_sql(definition) Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode! return unless async_index_creation_available? table_name, index_name = extract_table_and_index_names_from_concurrent_index!(definition) if index_name_exists?(table_name, index_name) Gitlab::AppLogger.warn( message: 'Index not prepared because it already exists', table_name: table_name, index_name: index_name) return end async_index = Gitlab::Database::AsyncIndexes::PostgresAsyncIndex.find_or_create_by!(name: index_name) do |rec| rec.table_name = table_name rec.definition = definition.to_s.strip end Gitlab::AppLogger.info( message: 'Prepared index for async creation', table_name: async_index.table_name, index_name: async_index.name) async_index end |
#prepare_async_index_removal(table_name, column_name, options = {}) ⇒ Object
Prepares an index for asynchronous destruction.
Stores the index information in the postgres_async_indexes table to be removed later. The index will be always be removed CONCURRENTLY, so that option does not need to be given. Except for partitioned tables where indexes cannot be dropped using this option. www.postgresql.org/docs/current/sql-dropindex.html
If the requested index has already been removed, it is not stored in the table for asynchronous destruction.
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/gitlab/database/async_indexes/migration_helpers.rb', line 142 def prepare_async_index_removal(table_name, column_name, = {}) index_name = .fetch(:name) raise 'prepare_async_index_removal must get an index name defined' if index_name.blank? unless index_exists?(table_name, column_name, **) Gitlab::AppLogger.warn "Index not removed because it does not exist (this may be due to an aborted migration or similar): table_name: #{table_name}, index_name: #{index_name}" return end definition = if table_partitioned?(table_name) "DROP INDEX #{quote_column_name(index_name)}" else "DROP INDEX CONCURRENTLY #{quote_column_name(index_name)}" end async_index = PostgresAsyncIndex.find_or_create_by!(name: index_name) do |rec| rec.table_name = table_name rec.definition = definition end Gitlab::AppLogger.info( message: 'Prepared index for async destruction', table_name: async_index.table_name, index_name: async_index.name ) async_index end |
#unprepare_async_index(table_name, column_name, **options) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 |
# File 'lib/gitlab/database/async_indexes/migration_helpers.rb', line 9 def unprepare_async_index(table_name, column_name, **) Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode! return unless async_index_creation_available? index_name = [:name] || index_name(table_name, column_name) raise 'Specifying index name is mandatory - specify name: argument' unless index_name unprepare_async_index_by_name(table_name, index_name) end |
#unprepare_async_index_by_name(table_name, index_name, **options) ⇒ Object
21 22 23 24 25 26 27 28 29 |
# File 'lib/gitlab/database/async_indexes/migration_helpers.rb', line 21 def unprepare_async_index_by_name(table_name, index_name, **) Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode! return unless async_index_creation_available? PostgresAsyncIndex.find_by(name: index_name).try do |async_index| async_index.destroy! end end |