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

update_repository_storage_methods.rb « concerns « services « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: dca38abf7af7bceeb3c7c25945836230cc82e23d (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
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# frozen_string_literal: true

module UpdateRepositoryStorageMethods
  include Gitlab::Utils::StrongMemoize

  Error = Class.new(StandardError)

  attr_reader :repository_storage_move

  delegate :container, :source_storage_name, :destination_storage_name, to: :repository_storage_move

  def initialize(repository_storage_move)
    @repository_storage_move = repository_storage_move
  end

  def execute
    response = repository_storage_move.with_lock do
      next ServiceResponse.success unless repository_storage_move.scheduled?

      repository_storage_move.start!

      nil
    end

    return response if response

    unless same_filesystem?
      mirror_repositories

      repository_storage_move.transaction do
        mirror_object_pool(destination_storage_name)
      end
    end

    repository_storage_move.transaction do
      repository_storage_move.finish_replication!

      track_repository(destination_storage_name)
    end

    remove_old_paths unless same_filesystem?

    repository_storage_move.finish_cleanup!

    ServiceResponse.success
  rescue StandardError => e
    repository_storage_move.do_fail!

    Gitlab::ErrorTracking.track_and_raise_exception(e, container_klass: container.class.to_s, container_path: container.full_path)
  end

  private

  def track_repository(destination_shard)
    raise NotImplementedError
  end

  def mirror_repositories
    raise NotImplementedError
  end

  def mirror_object_pool(_destination_shard)
    # no-op, redefined for Projects::UpdateRepositoryStorageService
    nil
  end

  def mirror_repository(type:)
    unless wait_for_pushes(type)
      raise Error, s_('UpdateRepositoryStorage|Timeout waiting for %{type} repository pushes') % { type: type.name }
    end

    repository = type.repository_for(container)
    full_path = repository.full_path
    raw_repository = repository.raw
    checksum = repository.checksum

    # Initialize a git repository on the target path
    new_repository = Gitlab::Git::Repository.new(
      destination_storage_name,
      raw_repository.relative_path,
      raw_repository.gl_repository,
      full_path
    )

    new_repository.replicate(raw_repository)
    new_checksum = new_repository.checksum

    if checksum != new_checksum
      raise Error, s_('UpdateRepositoryStorage|Failed to verify %{type} repository checksum from %{old} to %{new}') % { type: type.name, old: checksum, new: new_checksum }
    end
  end

  def same_filesystem?
    strong_memoize(:same_filesystem) do
      Gitlab::GitalyClient.filesystem_id(source_storage_name) == Gitlab::GitalyClient.filesystem_id(destination_storage_name)
    end
  end

  def remove_old_paths
    if container.repository_exists?
      Gitlab::Git::Repository.new(
        source_storage_name,
        "#{container.disk_path}.git",
        nil,
        nil
      ).remove
    end
  end

  def wait_for_pushes(type)
    reference_counter = container.reference_counter(type: type)

    # Try for 30 seconds, polling every 10
    3.times do
      return true if reference_counter.value == 0

      sleep 10
    end

    false
  end
end