Commit 9a63b10c authored by Patrick Steinhardt's avatar Patrick Steinhardt

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
...@@ -44,8 +44,6 @@ module Geo ...@@ -44,8 +44,6 @@ module Geo
log_error(message, error) log_error(message, error)
registry.fail_sync!(message, error, attrs) registry.fail_sync!(message, error, attrs)
repository.clean_stale_repository_files
end end
def start_registry_sync! def start_registry_sync!
......
...@@ -168,8 +168,6 @@ module Geo ...@@ -168,8 +168,6 @@ module Geo
registry = replicator.registry registry = replicator.registry
registry.force_to_redownload = force_to_redownload registry.force_to_redownload = force_to_redownload
registry.failed!(message: message, error: error) registry.failed!(message: message, error: error)
repository.clean_stale_repository_files
end end
def download_time_in_seconds def download_time_in_seconds
......
...@@ -181,8 +181,6 @@ module Geo ...@@ -181,8 +181,6 @@ module Geo
log_error(message, error) log_error(message, error)
registry.fail_sync!(type, message, error, attrs) registry.fail_sync!(type, message, error, attrs)
repository.clean_stale_repository_files
end end
def type def type
......
...@@ -226,12 +226,6 @@ RSpec.describe Geo::FrameworkRepositorySyncService, :geo do ...@@ -226,12 +226,6 @@ RSpec.describe Geo::FrameworkRepositorySyncService, :geo do
last_sync_failure: 'Error syncing repository: shell error' last_sync_failure: 'Error syncing repository: shell error'
) )
end end
it 'calls repository cleanup' do
expect(repository).to receive(:clean_stale_repository_files)
subject.execute
end
end end
end end
......
...@@ -285,12 +285,6 @@ RSpec.describe Geo::RepositorySyncService, :geo do ...@@ -285,12 +285,6 @@ RSpec.describe Geo::RepositorySyncService, :geo do
last_repository_sync_failure: 'Error syncing repository: shell error' last_repository_sync_failure: 'Error syncing repository: shell error'
) )
end end
it 'calls repository cleanup' do
expect(repository).to receive(:clean_stale_repository_files)
subject.execute
end
end end
end end
......
...@@ -224,12 +224,6 @@ RSpec.describe Geo::WikiSyncService, :geo do ...@@ -224,12 +224,6 @@ RSpec.describe Geo::WikiSyncService, :geo do
last_wiki_sync_failure: 'Error syncing wiki repository: shell error' last_wiki_sync_failure: 'Error syncing wiki repository: shell error'
) )
end end
it 'calls repository cleanup' do
expect(repository).to receive(:clean_stale_repository_files)
subject.execute
end
end end
context 'no Wiki repository' do context 'no Wiki repository' do
......
...@@ -972,18 +972,6 @@ module Gitlab ...@@ -972,18 +972,6 @@ module Gitlab
@praefect_info_client ||= Gitlab::GitalyClient::PraefectInfoService.new(self) @praefect_info_client ||= Gitlab::GitalyClient::PraefectInfoService.new(self)
end 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) def branch_names_contains_sha(sha)
gitaly_ref_client.branch_names_contains_sha(sha) gitaly_ref_client.branch_names_contains_sha(sha)
end end
......
...@@ -328,11 +328,6 @@ module Gitlab ...@@ -328,11 +328,6 @@ module Gitlab
raise ForbiddenError, error_message(:push_code) raise ForbiddenError, error_message(:push_code)
end end
else 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! check_access!
end end
end end
...@@ -467,11 +462,6 @@ module Gitlab ...@@ -467,11 +462,6 @@ module Gitlab
def check_push_size! def check_push_size!
return unless check_size_limit? 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 # 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 # 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 # doable if GIT_OBJECT_DIRECTORY_RELATIVE env var is set and happens
......
...@@ -21,11 +21,6 @@ module Gitlab ...@@ -21,11 +21,6 @@ module Gitlab
response.exists response.exists
end 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:) def garbage_collect(create_bitmap, prune:)
request = Gitaly::GarbageCollectRequest.new(repository: @gitaly_repo, create_bitmap: create_bitmap, prune: 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) GitalyClient.call(@storage, :repository_service, :garbage_collect, request, timeout: GitalyClient.long_timeout)
......
...@@ -2252,44 +2252,6 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do ...@@ -2252,44 +2252,6 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
end end
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 describe '#squash' do
let(:branch_name) { 'fix' } let(:branch_name) { 'fix' }
let(:start_sha) { '4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6' } let(:start_sha) { '4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6' }
......
...@@ -1008,11 +1008,6 @@ RSpec.describe Gitlab::GitAccess do ...@@ -1008,11 +1008,6 @@ RSpec.describe Gitlab::GitAccess do
end end
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 it 'avoids N+1 queries', :request_store do
# Run this once to establish a baseline. Cached queries should get # Run this once to establish a baseline. Cached queries should get
# cached, so that when we introduce another change we shouldn't see # cached, so that when we introduce another change we shouldn't see
......
...@@ -21,16 +21,6 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do ...@@ -21,16 +21,6 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
end end
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 describe '#garbage_collect' do
it 'sends a garbage_collect message' do it 'sends a garbage_collect message' do
expect_any_instance_of(Gitaly::RepositoryService::Stub) expect_any_instance_of(Gitaly::RepositoryService::Stub)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment