Clean up DownloadWithCacheManager’s cache at most every five minutes — it’s very expensive to do it on every request. This dramatically helps sidebar scrolling performance when you have a couple thousand feeds all trying to get their favicons.

This commit is contained in:
Brent Simmons 2017-12-13 21:18:20 -08:00
parent e6dee88e2e
commit b04876185d

View File

@ -65,11 +65,6 @@ private struct WebCacheRecord {
let dateDownloaded: Date
let data: Data
let response: URLResponse
func isExpired(_ timeToLive: TimeInterval) -> Bool {
return Date().timeIntervalSince(dateDownloaded) > timeToLive
}
}
private final class WebCache {
@ -77,18 +72,19 @@ private final class WebCache {
private var cache = [URL: WebCacheRecord]()
func cleanup(_ cleanupInterval: TimeInterval) {
let cutoffDate = Date(timeInterval: -cleanupInterval, since: Date())
cache.keys.forEach { (key) in
let cacheRecord = self[key]!
if shouldDelete(cacheRecord, cleanupInterval) {
if shouldDelete(cacheRecord, cutoffDate) {
cache[key] = nil
}
}
}
private func shouldDelete(_ cacheRecord: WebCacheRecord, _ cleanupInterval: TimeInterval) -> Bool {
private func shouldDelete(_ cacheRecord: WebCacheRecord, _ cutoffDate: Date) -> Bool {
return Date().timeIntervalSince(cacheRecord.dateDownloaded) > cleanupInterval
return cacheRecord.dateDownloaded < cutoffDate
}
subscript(_ url: URL) -> WebCacheRecord? {
@ -115,26 +111,24 @@ private final class DownloadWithCacheManager {
static let shared = DownloadWithCacheManager()
private var cache = WebCache()
private static let timeToLive: TimeInterval = 10 * 60 // 10 minutes
private static let cleanupInterval: TimeInterval = 30 * 60 // 30 minutes
private static let cleanupInterval: TimeInterval = 5 * 60 // clean up the cache at most every 5 minutes
private var lastCleanupDate = Date()
func download(_ url: URL, _ callback: @escaping OneShotDownloadCallback) {
cache.cleanup(DownloadWithCacheManager.cleanupInterval)
if lastCleanupDate.timeIntervalSinceNow < -(5 * 60) {
lastCleanupDate = Date()
cache.cleanup(DownloadWithCacheManager.timeToLive)
}
let cacheRecord: WebCacheRecord? = cache[url]
if let cacheRecord = cacheRecord, !cacheRecord.isExpired(DownloadWithCacheManager.timeToLive) {
if let cacheRecord = cacheRecord {
callback(cacheRecord.data, cacheRecord.response, nil)
return
}
OneShotDownloadManager.shared.download(url) { (data, response, error) in
if let _ = error, let cacheRecord = cacheRecord {
// In the case where a cache record has expired, but the download returned an error, we use the cache record anyway. By design.
callback(cacheRecord.data, cacheRecord.response, nil)
return
}
if let data = data, let response = response, response.statusIsOK, error == nil {
let cacheRecord = WebCacheRecord(url: url, dateDownloaded: Date(), data: data, response: response)
self.cache[url] = cacheRecord