diff options
Diffstat (limited to 'lib/gitlab/database/partitioning')
-rw-r--r-- | lib/gitlab/database/partitioning/monthly_strategy.rb | 4 | ||||
-rw-r--r-- | lib/gitlab/database/partitioning/partition_manager.rb | 13 | ||||
-rw-r--r-- | lib/gitlab/database/partitioning/sliding_list_strategy.rb | 53 |
3 files changed, 60 insertions, 10 deletions
diff --git a/lib/gitlab/database/partitioning/monthly_strategy.rb b/lib/gitlab/database/partitioning/monthly_strategy.rb index 9c8cccb3dc6..0f08a47d754 100644 --- a/lib/gitlab/database/partitioning/monthly_strategy.rb +++ b/lib/gitlab/database/partitioning/monthly_strategy.rb @@ -40,6 +40,10 @@ module Gitlab # No-op, required by the partition manager end + def validate_and_fix + # No-op, required by the partition manager + end + private def desired_partitions diff --git a/lib/gitlab/database/partitioning/partition_manager.rb b/lib/gitlab/database/partitioning/partition_manager.rb index 3ee9a193b45..aac91eaadb1 100644 --- a/lib/gitlab/database/partitioning/partition_manager.rb +++ b/lib/gitlab/database/partitioning/partition_manager.rb @@ -22,15 +22,13 @@ module Gitlab connection_name: @connection_name ) - # Double-checking before getting the lease: - # The prevailing situation is no missing partitions and no extra partitions - return if missing_partitions.empty? && extra_partitions.empty? - only_with_exclusive_lease(model, lease_key: MANAGEMENT_LEASE_KEY) do - partitions_to_create = missing_partitions - create(partitions_to_create) unless partitions_to_create.empty? + model.partitioning_strategy.validate_and_fix + partitions_to_create = missing_partitions partitions_to_detach = extra_partitions + + create(partitions_to_create) unless partitions_to_create.empty? detach(partitions_to_detach) unless partitions_to_detach.empty? end rescue StandardError => e @@ -119,7 +117,8 @@ module Gitlab parent_table_identifier = "#{connection.current_schema}.#{partition.table}" if (example_fk = PostgresForeignKey.by_referenced_table_identifier(parent_table_identifier).first) - raise UnsafeToDetachPartitionError, "Cannot detach #{partition.partition_name}, it would block while checking foreign key #{example_fk.name} on #{example_fk.constrained_table_identifier}" + raise UnsafeToDetachPartitionError, "Cannot detach #{partition.partition_name}, it would block while " \ + "checking foreign key #{example_fk.name} on #{example_fk.constrained_table_identifier}" end end diff --git a/lib/gitlab/database/partitioning/sliding_list_strategy.rb b/lib/gitlab/database/partitioning/sliding_list_strategy.rb index e9865fb91d6..5cf32d3272c 100644 --- a/lib/gitlab/database/partitioning/sliding_list_strategy.rb +++ b/lib/gitlab/database/partitioning/sliding_list_strategy.rb @@ -48,9 +48,12 @@ module Gitlab default_value = current_default_value if extra.any? { |p| p.value == default_value } - Gitlab::AppLogger.error(message: "Inconsistent partition detected: partition with value #{current_default_value} should not be deleted because it's used as the default value.", - partition_number: current_default_value, - table_name: model.table_name) + Gitlab::AppLogger.error( + message: "Inconsistent partition detected: partition with value #{current_default_value} should " \ + "not be deleted because it's used as the default value.", + partition_number: current_default_value, + table_name: model.table_name + ) extra = extra.reject { |p| p.value == default_value } end @@ -73,6 +76,42 @@ module Gitlab current_partitions.empty? end + def validate_and_fix + return unless Feature.enabled?(:fix_sliding_list_partitioning) + return if no_partitions_exist? + + old_default_value = current_default_value + expected_default_value = active_partition.value + + if old_default_value != expected_default_value + with_lock_retries do + model.connection.execute("LOCK TABLE #{model.table_name} IN ACCESS EXCLUSIVE MODE") + + old_default_value = current_default_value + expected_default_value = active_partition.value + + if old_default_value == expected_default_value + Gitlab::AppLogger.warn( + message: "Table partitions or partition key default value have been changed by another process", + table_name: table_name, + default_value: expected_default_value + ) + raise ActiveRecord::Rollback + end + + model.connection.change_column_default(model.table_name, partitioning_key, expected_default_value) + Gitlab::AppLogger.warn( + message: "Fixed default value of sliding_list_strategy partitioning_key", + column: partitioning_key, + table_name: table_name, + connection_name: model.connection.pool.db_config.name, + old_value: old_default_value, + new_value: expected_default_value + ) + end + end + end + private def current_default_value @@ -95,6 +134,14 @@ module Gitlab raise "Add #{partitioning_key} to #{model.name}.ignored_columns to use it with SlidingListStrategy" end end + + def with_lock_retries(&block) + Gitlab::Database::WithLockRetries.new( + klass: self.class, + logger: Gitlab::AppLogger, + connection: model.connection + ).run(&block) + end end end end |