2020-03-23 12:09:47 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module Gitlab
|
|
|
|
module Cleanup
|
|
|
|
class OrphanLfsFileReferences
|
|
|
|
include Gitlab::Utils::StrongMemoize
|
|
|
|
|
2021-01-25 12:09:07 +00:00
|
|
|
attr_reader :project, :dry_run, :logger
|
2020-03-23 12:09:47 +00:00
|
|
|
|
|
|
|
DEFAULT_REMOVAL_LIMIT = 1000
|
|
|
|
|
2021-01-25 12:09:07 +00:00
|
|
|
def initialize(project, dry_run: true, logger: nil)
|
2020-03-23 12:09:47 +00:00
|
|
|
@project = project
|
|
|
|
@dry_run = dry_run
|
2020-09-08 09:08:31 +00:00
|
|
|
@logger = logger || Gitlab::AppLogger
|
2020-03-23 12:09:47 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def run!
|
|
|
|
log_info("Looking for orphan LFS files for project #{project.name_with_namespace}")
|
|
|
|
|
2020-09-24 15:09:51 +00:00
|
|
|
if project.lfs_objects.empty?
|
|
|
|
log_info("Project #{project.name_with_namespace} is linked to 0 LFS objects. Nothing to do")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2020-03-23 12:09:47 +00:00
|
|
|
remove_orphan_references
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def remove_orphan_references
|
2020-09-07 12:08:27 +00:00
|
|
|
invalid_references = project.lfs_objects_projects.lfs_object_in(orphan_objects)
|
2020-03-23 12:09:47 +00:00
|
|
|
|
|
|
|
if dry_run
|
|
|
|
log_info("Found invalid references: #{invalid_references.count}")
|
|
|
|
else
|
|
|
|
count = 0
|
|
|
|
invalid_references.each_batch(of: limit || DEFAULT_REMOVAL_LIMIT) do |relation|
|
|
|
|
count += relation.delete_all
|
|
|
|
end
|
|
|
|
|
2020-05-19 15:08:04 +00:00
|
|
|
ProjectCacheWorker.perform_async(project.id, [], [:lfs_objects_size])
|
|
|
|
|
2020-03-23 12:09:47 +00:00
|
|
|
log_info("Removed invalid references: #{count}")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-09-07 12:08:27 +00:00
|
|
|
def orphan_objects
|
|
|
|
# Get these first so racing with a git push can't remove any LFS objects
|
|
|
|
oids = project.lfs_objects_oids
|
2020-03-23 12:09:47 +00:00
|
|
|
|
2020-09-07 12:08:27 +00:00
|
|
|
repos = [
|
|
|
|
project.repository,
|
|
|
|
project.design_repository,
|
|
|
|
project.wiki.repository
|
|
|
|
].select(&:exists?)
|
2020-03-23 12:09:47 +00:00
|
|
|
|
2020-09-07 12:08:27 +00:00
|
|
|
repos.flat_map do |repo|
|
|
|
|
oids -= repo.gitaly_blob_client.get_all_lfs_pointers.map(&:lfs_oid)
|
2020-03-23 12:09:47 +00:00
|
|
|
end
|
|
|
|
|
2020-09-07 12:08:27 +00:00
|
|
|
# The remaining OIDs are not used by any repository, so are orphans
|
|
|
|
LfsObject.for_oids(oids)
|
2020-03-23 12:09:47 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def log_info(msg)
|
|
|
|
logger.info("#{'[DRY RUN] ' if dry_run}#{msg}")
|
|
|
|
end
|
2021-01-25 12:09:07 +00:00
|
|
|
|
|
|
|
def limit
|
|
|
|
ENV['LIMIT']&.to_i
|
|
|
|
end
|
2020-03-23 12:09:47 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|