Add calculateOrphanedBlobsSize() to calculate the size of orphaned blobs (#428)

Adds `calculateOrphanedBlobsSize()` to calculate the size of orphaned
blobs, will need this to include them under size and reclaimable space
for images in the `container system df` command so it matches up with
what `container image prune` frees up on disk.
This commit is contained in:
Raj
2025-11-21 14:50:28 -08:00
committed by GitHub
parent 836b699a91
commit 35ebe365ba
@@ -141,6 +141,15 @@ extension ImageStore {
}
}
/// Calculate the size of orphaned blobs without deleting them.
///
/// - Returns: The total size in bytes of blobs that are not referenced by any image.
public func calculateOrphanedBlobsSize() async throws -> UInt64 {
try await self.lock.withLock { lockCtx in
try await self._calculateOrphanedBlobsSize(lockCtx)
}
}
@discardableResult
private func _cleanupOrphanedBlobs(_ lock: AsyncLock.Context) async throws -> (deleted: [String], freed: UInt64) {
let images = try await self.list()
@@ -152,6 +161,39 @@ extension ImageStore {
return (deleted, size)
}
private func _calculateOrphanedBlobsSize(_ lock: AsyncLock.Context) async throws -> UInt64 {
let images = try await self.list()
var referenced: [String] = []
for image in images {
try await referenced.append(contentsOf: image.referencedDigests().uniqued())
}
// Calculate size of blobs not in the referenced list
let referencedSet = Set(referenced.map { $0.trimmingDigestPrefix })
let blobsPath = self.path.appendingPathComponent("content/blobs/sha256")
let fileManager = FileManager.default
let allBlobs = try fileManager.contentsOfDirectory(
at: blobsPath,
includingPropertiesForKeys: [.fileSizeKey],
options: [.skipsHiddenFiles]
)
var orphanedSize: UInt64 = 0
for blobURL in allBlobs {
let digest = blobURL.lastPathComponent
if !referencedSet.contains(digest) {
if let resourceValues = try? blobURL.resourceValues(forKeys: [.fileSizeKey]),
let size = resourceValues.fileSize
{
orphanedSize += UInt64(size)
}
}
}
return orphanedSize
}
/// Tag an existing image such that it can be referenced by another name.
///
/// - Parameters: