mirror of
https://github.com/apple/container.git
synced 2026-07-15 14:07:04 +00:00
149 lines
5.2 KiB
Swift
149 lines
5.2 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
// Copyright © 2025 Apple Inc. and the container project authors. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import ContainerBuildIR
|
|
import ContainerBuildSnapshotter
|
|
import ContainerizationOCI
|
|
import Foundation
|
|
|
|
/// Protocol for build cache implementations.
|
|
///
|
|
/// The cache stores operation results to avoid redundant execution.
|
|
///
|
|
/// PERFORMANCE OPTIMIZATION OPPORTUNITIES (from Design.md):
|
|
///
|
|
/// 1. Graph-Level Cache Analysis:
|
|
/// - Add a method to check multiple cache keys in parallel before execution starts
|
|
/// - Return a map of cache hits/misses for the entire build graph
|
|
/// - Example: func checkBatch(_ keys: [CacheKey]) async -> [CacheKey: Bool]
|
|
///
|
|
/// 2. Cache-Aware Graph Transformation:
|
|
/// - Implement a CachedScheduler that pre-processes the build graph
|
|
/// - Replace cached operations with lightweight cache retrieval operations
|
|
/// - Skip entire dependency chains if final results are cached
|
|
///
|
|
/// 3. Speculative Cache Warming:
|
|
/// - Add methods to prefetch likely cache entries based on build patterns
|
|
/// - Support background cache population for common operations
|
|
///
|
|
/// 4. Parallel Cache Operations:
|
|
/// - Batch get/put operations for multiple artifacts
|
|
/// - Use Swift concurrency for non-blocking cache access
|
|
/// - Example: func getBatch(_ keys: [CacheKey]) async -> [CacheKey: CachedResult?]
|
|
///
|
|
/// 5. Cache Metadata for Scheduling:
|
|
/// - Expose cache hit probability estimates
|
|
/// - Provide operation cost estimates based on historical data
|
|
/// - Enable scheduler to make smarter execution decisions
|
|
///
|
|
/// Current implementation is functionally correct but checks cache sequentially
|
|
/// during execution rather than optimizing the execution graph based on cache state.
|
|
public protocol BuildCache: Sendable {
|
|
/// Look up a cached result for an operation.
|
|
///
|
|
/// - Parameters:
|
|
/// - key: The cache key for the operation
|
|
/// - operation: The operation being cached
|
|
/// - Returns: The cached result if found, nil otherwise
|
|
func get(_ key: CacheKey, for operation: ContainerBuildIR.Operation) async -> CachedResult?
|
|
|
|
/// Store a result in the cache.
|
|
///
|
|
/// - Parameters:
|
|
/// - result: The result to cache
|
|
/// - key: The cache key
|
|
/// - operation: The operation that produced the result
|
|
func put(_ result: CachedResult, key: CacheKey, for operation: ContainerBuildIR.Operation) async
|
|
|
|
/// Get cache statistics.
|
|
///
|
|
/// - Returns: Statistics about cache usage and performance
|
|
func statistics() async -> CacheStatistics
|
|
}
|
|
|
|
/// A key for cache lookups.
|
|
public struct CacheKey: Hashable, Sendable {
|
|
/// The digest of the operation.
|
|
public let operationDigest: ContainerBuildIR.Digest
|
|
|
|
/// Input digests from dependencies.
|
|
public let inputDigests: [ContainerBuildIR.Digest]
|
|
|
|
/// Platform identifier.
|
|
public let platform: Platform
|
|
|
|
public init(
|
|
operationDigest: ContainerBuildIR.Digest,
|
|
inputDigests: [ContainerBuildIR.Digest] = [],
|
|
platform: Platform
|
|
) {
|
|
self.operationDigest = operationDigest
|
|
self.inputDigests = inputDigests
|
|
self.platform = platform
|
|
}
|
|
}
|
|
|
|
/// A cached execution result.
|
|
public struct CachedResult: Sendable {
|
|
/// The snapshot produced by the operation.
|
|
public let snapshot: Snapshot
|
|
|
|
/// Environment changes made by the operation.
|
|
public let environmentChanges: [String: EnvironmentValue]
|
|
|
|
/// Metadata changes.
|
|
public let metadataChanges: [String: String]
|
|
|
|
public init(
|
|
snapshot: Snapshot,
|
|
environmentChanges: [String: EnvironmentValue] = [:],
|
|
metadataChanges: [String: String] = [:]
|
|
) {
|
|
self.snapshot = snapshot
|
|
self.environmentChanges = environmentChanges
|
|
self.metadataChanges = metadataChanges
|
|
}
|
|
}
|
|
|
|
/// A no-op cache implementation that never caches.
|
|
public struct NoOpBuildCache: BuildCache {
|
|
public init() {}
|
|
|
|
public func get(_ key: CacheKey, for operation: ContainerBuildIR.Operation) async -> CachedResult? {
|
|
nil
|
|
}
|
|
|
|
public func put(_ result: CachedResult, key: CacheKey, for operation: ContainerBuildIR.Operation) async {
|
|
// No-op
|
|
}
|
|
|
|
public func statistics() async -> CacheStatistics {
|
|
CacheStatistics(
|
|
entryCount: 0,
|
|
totalSize: 0,
|
|
hitRate: 0,
|
|
oldestEntryAge: 0,
|
|
mostRecentEntryAge: 0,
|
|
evictionPolicy: "none",
|
|
averageEntrySize: 0,
|
|
operationMetrics: .empty,
|
|
errorCount: 0,
|
|
lastGCTime: nil,
|
|
shardInfo: nil
|
|
)
|
|
}
|
|
}
|