72 lines
1.9 KiB
Swift
72 lines
1.9 KiB
Swift
//
|
|
// CachingDiskStorage.swift
|
|
// Tusker
|
|
//
|
|
// Created by Shadowfacts on 1/17/21.
|
|
// Copyright © 2021 Shadowfacts. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import Cache
|
|
|
|
/// This class wraps a `DiskStorage` and maintains an in-memory cache of whether objects
|
|
/// exist on disk to avoid unnecessary disk I/O when calling synchronous methods like
|
|
/// `existsObject(forKey:)`.
|
|
class CachingDiskStorage<T>: StorageAware {
|
|
|
|
private let storage: DiskStorage<T>
|
|
private var files = [String: FileState]()
|
|
|
|
init(config: DiskConfig, transformer: Transformer<T>) throws {
|
|
storage = try DiskStorage(config: config, transformer: transformer)
|
|
}
|
|
|
|
private func state(for key: String) -> FileState {
|
|
return files[key] ?? .unknown
|
|
}
|
|
|
|
func entry(forKey key: String) throws -> Entry<T> {
|
|
if state(for: key) == .doesNotExist {
|
|
throw StorageError.notFound
|
|
}
|
|
return try storage.entry(forKey: key)
|
|
}
|
|
|
|
func existsObject(forKey key: String) throws -> Bool {
|
|
switch state(for: key) {
|
|
case .unknown:
|
|
return try storage.existsObject(forKey: key)
|
|
case .exists:
|
|
return true
|
|
case .doesNotExist:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func removeObject(forKey key: String) throws {
|
|
try storage.removeObject(forKey: key)
|
|
files[key] = .doesNotExist
|
|
}
|
|
|
|
func setObject(_ object: T, forKey key: String, expiry: Expiry? = nil) throws {
|
|
try storage.setObject(object, forKey: key, expiry: expiry)
|
|
files[key] = .exists
|
|
}
|
|
|
|
func removeAll() throws {
|
|
try storage.removeAll()
|
|
files.removeAll()
|
|
}
|
|
|
|
func removeExpiredObjects() throws {
|
|
try storage.removeExpiredObjects()
|
|
}
|
|
|
|
}
|
|
|
|
extension CachingDiskStorage {
|
|
private enum FileState {
|
|
case unknown, exists, doesNotExist
|
|
}
|
|
}
|