Welcome to mirror list, hosted at ThFree Co, Russian Federation.

deletion.rb « batched_git_ref_updates « models « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 61bba8aeba9346341e78b70428b58854dd7e6b9d (plain)
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
# frozen_string_literal: true

module BatchedGitRefUpdates
  class Deletion < ApplicationRecord
    PARTITION_DURATION = 1.day

    include IgnorableColumns
    include BulkInsertSafe
    include PartitionedTable
    include EachBatch

    self.table_name = 'p_batched_git_ref_updates_deletions'
    self.primary_key = :id
    self.sequence_name = :to_be_deleted_git_refs_id_seq

    # This column must be ignored otherwise Rails will cache the default value and `bulk_insert!` will start saving
    # incorrect partition_id.
    ignore_column :partition_id, remove_with: '3000.0', remove_after: '3000-01-01'

    belongs_to :project, inverse_of: :to_be_deleted_git_refs

    scope :for_partition, ->(partition) { where(partition_id: partition) }
    scope :for_project, ->(project_id) { where(project_id: project_id) }
    scope :select_ref_and_identity, -> { select(:ref, :id, arel_table[:partition_id].as('partition')) }

    partitioned_by :partition_id, strategy: :sliding_list,
      next_partition_if: ->(active_partition) do
        oldest_record_in_partition = Deletion
          .select(:id, :created_at)
          .for_partition(active_partition.value)
          .order(:id)
          .limit(1)
          .take

        oldest_record_in_partition.present? &&
          oldest_record_in_partition.created_at < PARTITION_DURATION.ago
      end,
      detach_partition_if: ->(partition) do
        !Deletion
          .for_partition(partition.value)
          .status_pending
          .exists?
      end

    enum status: { pending: 1, processed: 2 }, _prefix: :status

    def self.mark_records_processed(records)
      update_by_partition(records) do |partitioned_scope|
        partitioned_scope.update_all(status: :processed)
      end
    end

    # Your scope must select_ref_and_identity before calling this method as it relies on partition being explicitly
    # selected
    def self.update_by_partition(records)
      records.group_by(&:partition).each do |partition, records_within_partition|
        partitioned_scope = status_pending
          .for_partition(partition)
          .where(id: records_within_partition.map(&:id))

        yield(partitioned_scope)
      end
    end

    private_class_method :update_by_partition
  end
end