File: partition.rb

package info (click to toggle)
gitlab 17.6.5-19
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 629,368 kB
  • sloc: ruby: 1,915,304; javascript: 557,307; sql: 60,639; xml: 6,509; sh: 4,567; makefile: 1,239; python: 406
file content (94 lines) | stat: -rw-r--r-- 2,445 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
# frozen_string_literal: true

module Ci
  class Partition < Ci::ApplicationRecord
    MAX_PARTITION_SIZE = 100.gigabytes

    INITIAL_PARTITION_VALUE = 100
    LATEST_PARTITION_VALUE = 102
    DEFAULT_PARTITION_VALUES = (INITIAL_PARTITION_VALUE..LATEST_PARTITION_VALUE).to_a.freeze

    validates :id, :status, presence: true
    validates :status, uniqueness: { if: ->(partition) { partition.status_changed? && partition.current? } }

    state_machine :status, initial: :preparing do
      state :preparing, value: 0
      state :ready, value: 1
      state :current, value: 2
      state :active, value: 3

      event :ready do
        transition preparing: :ready
      end

      event :switch_writes do
        transition ready: :current
      end

      before_transition [:ready] => :current do
        Ci::Partition.with_status(:current).update_all(status: Ci::Partition.statuses[:active])
      end
    end

    scope :id_after, ->(partition_id) { where(arel_table[:id].gt(partition_id)) }

    class << self
      def statuses
        @statuses ||= state_machines[:status].states.to_h { |state| [state.name, state.value] }.freeze
      end

      def current
        with_status(:current).first
      end

      def create_next!
        create!(id: last.id.next, status: statuses[:preparing])
      end

      def next_available(partition_id)
        Ci::Partition
          .with_status(:ready)
          .id_after(partition_id)
          .order(id: :asc)
          .first
      end

      def provisioning(partition_id)
        Ci::Partition
          .with_status(:preparing)
          .id_after(partition_id)
          .order(id: :asc)
          .first
      end
    end

    def above_threshold?(threshold)
      with_ci_connection do
        Gitlab::Database::PostgresPartition
          .with_parent_tables(parent_table_names)
          .with_list_constraint(id)
          .above_threshold(threshold)
          .exists?
      end
    end

    def all_partitions_exist?
      with_ci_connection do
        Gitlab::Database::PostgresPartition
          .with_parent_tables(parent_table_names)
          .with_list_constraint(id)
          .count == parent_table_names.size
      end
    end

    private

    def with_ci_connection(&block)
      Gitlab::Database::SharedModel.using_connection(connection, &block)
    end

    def parent_table_names
      Ci::Partitionable.registered_models.map(&:table_name)
    end
  end
end