Skip to content
Snippets Groups Projects
Commit 9a63b10c authored by Patrick Steinhardt's avatar Patrick Steinhardt
Browse files

git: Stop calling Gitaly's Cleanup RPC

Historically, Gitaly easily ended up in states where the repository is
in a state such that many different Git commands failed. This is why
Gitaly provides a Cleanup RPC that cleans up any such data structures
which are known to cause problems, and we call it in many different
places.

There had been two main usecases for this:

    - Git is known to leave behind corrupted references in case of a
      hard shutdown because it doesn't fsync(3p) data to disk before
      renaming loose references into place. Such broken references may
      cause Git commands to fail which try to read them, and as such
      Gitaly used to perform housekeeping tasks where it walked through
      the repository to clean up any such corrupt references. Gitaly had
      to eventually remove this functionality from Cleanup though: in
      repositories hosted on NFS this was causing significant latency
      and thus caused timeouts. We thus don't do this anymore since
      7a1d224d0 (repository: Remove housekeeping from Cleanup RPC,
      2021-05-17).

    - Many of Gitaly's RPCs used to create worktrees to perform various
      operations. In some cases worktrees were pruned, but left behind
      broken references which as a result again caused corrupted
      references. The Cleanup RPC thus prunes any such per-worktree
      references and cleans up pointers to already-removed worktrees.
      Gitaly has since converted all RPCs except UserApplyPatch to not
      use worktrees anymore, and this remaining RPC is effectively
      unused: this week we had two calls of it across all of gitlab.com.

It is thus safe to say that the Cleanup RPC is effectively useless and
doesn't do anything. It doesn't clean up corrupted references, and
because we don't create worktrees we wouldn't ever need to clean them up
either. Furthermore, both of those actions are performed by other RPCs,
namely GarbageCollect and OptimizeRepository. The former one is
frequently executed by Rails, while the latter one is automatically
executed during our daily maintenance window on all repositories.

Let's thus stop calling Cleanup altogether such that its RPC can be
properly deprecated and removed in Gitaly.

Changelog: removed
parent 51b396f7
No related branches found
No related tags found
1 merge request!80485git: Stop calling Gitaly's Cleanup RPC
Showing
with 0 additions and 104 deletions
......@@ -44,8 +44,6 @@ def fail_registry_sync!(message, error, attrs = {})
log_error(message, error)
registry.fail_sync!(message, error, attrs)
repository.clean_stale_repository_files
end
def start_registry_sync!
......
......@@ -168,8 +168,6 @@ def fail_registry_sync!(message, error, force_to_redownload: false)
registry = replicator.registry
registry.force_to_redownload = force_to_redownload
registry.failed!(message: message, error: error)
repository.clean_stale_repository_files
end
def download_time_in_seconds
......
......@@ -181,8 +181,6 @@ def fail_registry_sync!(message, error, attrs = {})
log_error(message, error)
registry.fail_sync!(type, message, error, attrs)
repository.clean_stale_repository_files
end
def type
......
......@@ -226,12 +226,6 @@
last_sync_failure: 'Error syncing repository: shell error'
)
end
it 'calls repository cleanup' do
expect(repository).to receive(:clean_stale_repository_files)
subject.execute
end
end
end
......
......@@ -285,12 +285,6 @@
last_repository_sync_failure: 'Error syncing repository: shell error'
)
end
it 'calls repository cleanup' do
expect(repository).to receive(:clean_stale_repository_files)
subject.execute
end
end
end
......
......@@ -224,12 +224,6 @@
last_wiki_sync_failure: 'Error syncing wiki repository: shell error'
)
end
it 'calls repository cleanup' do
expect(repository).to receive(:clean_stale_repository_files)
subject.execute
end
end
context 'no Wiki repository' do
......
......@@ -972,18 +972,6 @@ def praefect_info_client
@praefect_info_client ||= Gitlab::GitalyClient::PraefectInfoService.new(self)
end
def clean_stale_repository_files
wrapped_gitaly_errors do
gitaly_repository_client.cleanup if exists?
end
rescue Gitlab::Git::CommandError => e # Don't fail if we can't cleanup
Gitlab::AppLogger.error("Unable to clean repository on storage #{storage} with relative path #{relative_path}: #{e.message}")
Gitlab::Metrics.counter(
:failed_repository_cleanup_total,
'Number of failed repository cleanup events'
).increment
end
def branch_names_contains_sha(sha)
gitaly_ref_client.branch_names_contains_sha(sha)
end
......
......@@ -328,11 +328,6 @@ def check_change_access!
raise ForbiddenError, error_message(:push_code)
end
else
# If there are worktrees with a HEAD pointing to a non-existent object,
# calls to `git rev-list --all` will fail in git 2.15+. This should also
# clear stale lock files.
project.repository.clean_stale_repository_files if project.present?
check_access!
end
end
......@@ -467,11 +462,6 @@ def check_size_before_push!
def check_push_size!
return unless check_size_limit?
# If there are worktrees with a HEAD pointing to a non-existent object,
# calls to `git rev-list --all` will fail in git 2.15+. This should also
# clear stale lock files.
repository.clean_stale_repository_files
# Use #check_repository_disk_size to get correct push size whenever a lot of changes
# gets pushed at the same time containing the same blobs. This is only
# doable if GIT_OBJECT_DIRECTORY_RELATIVE env var is set and happens
......
......@@ -21,11 +21,6 @@ def exists?
response.exists
end
def cleanup
request = Gitaly::CleanupRequest.new(repository: @gitaly_repo)
GitalyClient.call(@storage, :repository_service, :cleanup, request, timeout: GitalyClient.fast_timeout)
end
def garbage_collect(create_bitmap, prune:)
request = Gitaly::GarbageCollectRequest.new(repository: @gitaly_repo, create_bitmap: create_bitmap, prune: prune)
GitalyClient.call(@storage, :repository_service, :garbage_collect, request, timeout: GitalyClient.long_timeout)
......
......@@ -2252,44 +2252,6 @@ def merge_to_ref
end
end
describe '#clean_stale_repository_files' do
let(:worktree_id) { 'rebase-1' }
let(:gitlab_worktree_path) { File.join(repository_path, 'gitlab-worktree', worktree_id) }
let(:admin_dir) { File.join(repository_path, 'worktrees') }
it 'cleans up the files' do
create_worktree = %W[git -C #{repository_path} worktree add --detach #{gitlab_worktree_path} master]
raise 'preparation failed' unless system(*create_worktree, err: '/dev/null')
FileUtils.touch(gitlab_worktree_path, mtime: Time.now - 8.hours)
# git rev-list --all will fail in git 2.16 if HEAD is pointing to a non-existent object,
# but the HEAD must be 40 characters long or git will ignore it.
File.write(File.join(admin_dir, worktree_id, 'HEAD'), Gitlab::Git::BLANK_SHA)
expect(rev_list_all).to be(false)
repository.clean_stale_repository_files
expect(rev_list_all).to be(true)
expect(File.exist?(gitlab_worktree_path)).to be_falsey
end
def rev_list_all
system(*%W[git -C #{repository_path} rev-list --all], out: '/dev/null', err: '/dev/null')
end
it 'increments a counter upon an error' do
expect(repository.gitaly_repository_client).to receive(:cleanup).and_raise(Gitlab::Git::CommandError)
counter = double(:counter)
expect(counter).to receive(:increment)
expect(Gitlab::Metrics).to receive(:counter).with(:failed_repository_cleanup_total,
'Number of failed repository cleanup events').and_return(counter)
repository.clean_stale_repository_files
end
end
describe '#squash' do
let(:branch_name) { 'fix' }
let(:start_sha) { '4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6' }
......
......@@ -1008,11 +1008,6 @@ def self.run_permission_checks(permissions_matrix)
end
end
it 'cleans up the files' do
expect(project.repository).to receive(:clean_stale_repository_files).and_call_original
expect { push_access_check }.not_to raise_error
end
it 'avoids N+1 queries', :request_store do
# Run this once to establish a baseline. Cached queries should get
# cached, so that when we introduce another change we shouldn't see
......
......@@ -21,16 +21,6 @@
end
end
describe '#cleanup' do
it 'sends a cleanup message' do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
.to receive(:cleanup)
.with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
client.cleanup
end
end
describe '#garbage_collect' do
it 'sends a garbage_collect message' do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment