Commit ca5b6b48 authored by Kamil Trzciński's avatar Kamil Trzciński Committed by pbair

Support partitioning of `SharedModels`

`SharedModels` by design do live on many databases.
Do seamlessly support partitioning of such to automatically
traverse all supported databases as defined by configuration.
parent 6ad30931
......@@ -14,10 +14,12 @@ if Gitlab.ee?
else
Gitlab::Database::Partitioning.register_tables([
{
limit_connection_names: %i[main],
table_name: 'incident_management_pending_alert_escalations',
partitioned_column: :process_at, strategy: :monthly
},
{
limit_connection_names: %i[main],
table_name: 'incident_management_pending_issue_escalations',
partitioned_column: :process_at, strategy: :monthly
}
......@@ -30,6 +32,7 @@ unless Gitlab.jh?
# This should be synchronized with the following model:
# https://jihulab.com/gitlab-cn/gitlab/-/blob/main-jh/jh/app/models/phone/verification_code.rb
{
limit_connection_names: %i[main],
table_name: 'verification_codes',
partitioned_column: :created_at, strategy: :monthly
}
......
......@@ -14,17 +14,39 @@ module Gitlab
end
end
def each_model_connection(models)
def each_model_connection(models, &blk)
models.each do |model|
# If model is shared, iterate all available base connections
# Example: `LooseForeignKeys::DeletedRecord`
if model < ::Gitlab::Database::SharedModel
with_shared_model_connections(model, &blk)
else
with_model_connection(model, &blk)
end
end
end
private
def with_shared_model_connections(shared_model, &blk)
Gitlab::Database.database_base_models.each_pair do |connection_name, connection_model|
if shared_model.limit_connection_names
next unless shared_model.limit_connection_names.include?(connection_name)
end
with_shared_connection(connection_model.connection, connection_name) do
yield shared_model, connection_name
end
end
end
def with_model_connection(model, &blk)
connection_name = model.connection.pool.db_config.name
with_shared_connection(model.connection, connection_name) do
yield model, connection_name
end
end
end
private
def with_shared_connection(connection, connection_name)
Gitlab::Database::SharedModel.using_connection(connection) do
......
......@@ -3,19 +3,8 @@
module Gitlab
module Database
module Partitioning
class TableWithoutModel
include PartitionedTable::ClassMethods
attr_reader :table_name
def initialize(table_name:, partitioned_column:, strategy:)
@table_name = table_name
partitioned_by(partitioned_column, strategy: strategy)
end
def connection
Gitlab::Database::SharedModel.connection
end
class TableWithoutModel < Gitlab::Database::SharedModel
include PartitionedTable
end
class << self
......@@ -77,7 +66,15 @@ module Gitlab
def registered_for_sync
registered_models + registered_tables.map do |table|
TableWithoutModel.new(**table)
table_without_model(**table)
end
end
def table_without_model(table_name:, partitioned_column:, strategy:, limit_connection_names: nil)
Class.new(TableWithoutModel).tap do |klass|
klass.table_name = table_name
klass.partitioned_by(partitioned_column, strategy: strategy)
klass.limit_connection_names = limit_connection_names
end
end
end
......
......@@ -12,10 +12,15 @@ module Gitlab
def initialize(model)
@model = model
@connection_name = model.connection.pool.db_config.name
end
def sync_partitions
Gitlab::AppLogger.info(message: "Checking state of dynamic postgres partitions", table_name: model.table_name)
Gitlab::AppLogger.info(
message: "Checking state of dynamic postgres partitions",
table_name: model.table_name,
connection_name: @connection_name
)
# Double-checking before getting the lease:
# The prevailing situation is no missing partitions and no extra partitions
......@@ -29,10 +34,13 @@ module Gitlab
detach(partitions_to_detach) unless partitions_to_detach.empty?
end
rescue StandardError => e
Gitlab::AppLogger.error(message: "Failed to create / detach partition(s)",
Gitlab::AppLogger.error(
message: "Failed to create / detach partition(s)",
table_name: model.table_name,
exception_class: e.class,
exception_message: e.message)
exception_message: e.message,
connection_name: @connection_name
)
end
private
......@@ -98,9 +106,12 @@ module Gitlab
Postgresql::DetachedPartition.create!(table_name: partition.partition_name,
drop_after: RETAIN_DETACHED_PARTITIONS_FOR.from_now)
Gitlab::AppLogger.info(message: "Detached Partition",
Gitlab::AppLogger.info(
message: "Detached Partition",
partition_name: partition.partition_name,
table_name: partition.table)
table_name: partition.table,
connection_name: @connection_name
)
end
def assert_partition_detachable!(partition)
......
......@@ -6,6 +6,10 @@ module Gitlab
class SharedModel < ActiveRecord::Base
self.abstract_class = true
# if shared model is used, this allows to limit connections
# on which this model is being shared
class_attribute :limit_connection_names, default: nil
class << self
def using_connection(connection)
previous_connection = self.overriding_connection
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment