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
123
124
125
126
|
# 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
# `Projects::UpdateRepositoryStorageService`` expects the repository it is
# moving to have a `Project` as a container.
# This hack allows design repos to also be moved as part of a project move
# as before.
# The alternative to this hack is to setup a service like
# `Snippets::UpdateRepositoryStorageService' and a corresponding worker like
# `Snippets::UpdateRepositoryStorageWorker` for snippets.
#
# Gitlab issue: https://gitlab.com/gitlab-org/gitlab/-/issues/423429
repository = type.repository_for(type.design? ? container.design_management_repository : container)
full_path = repository.full_path
raw_repository = repository.raw
# 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
)
Repositories::ReplicateService.new(raw_repository).execute(new_repository, type.name)
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
|