@@ -30,8 +30,9 @@ actor Snapshot<AccessMode: _AccessMode> {
30
30
/// A cached instance of the manifest as last loaded from disk.
31
31
var cachedManifest : SnapshotManifest ?
32
32
33
- /// A cached instance of the current iteration as last loaded from disk.
34
- var cachedIteration : SnapshotIteration ?
33
+ /// Cache for the loaded iterations as last loaded from disk. ``isExtendedIterationCacheEnabled`` controls if multiple iterations are cached or not.
34
+ var cachedIterations : [ SnapshotIterationIdentifier : SnapshotIteration ] = [ : ]
35
+ var isExtendedIterationCacheEnabled : Bool
35
36
36
37
/// A pointer to the last manifest updater, so updates can be serialized after the last request.
37
38
var lastUpdateManifestTask : Task < Sendable , Error > ?
@@ -42,11 +43,13 @@ actor Snapshot<AccessMode: _AccessMode> {
42
43
init (
43
44
id: SnapshotIdentifier ,
44
45
persistence: DiskPersistence < AccessMode > ,
45
- isBackup: Bool = false
46
+ isBackup: Bool = false ,
47
+ isExtendedIterationCacheEnabled: Bool = false
46
48
) {
47
49
self . id = id
48
50
self . persistence = persistence
49
51
self . isBackup = isBackup
52
+ self . isExtendedIterationCacheEnabled = isExtendedIterationCacheEnabled
50
53
}
51
54
}
52
55
@@ -124,14 +127,25 @@ extension Snapshot {
124
127
}
125
128
}
126
129
130
+ func setExtendedIterationCacheEnabled( _ isEnabled: Bool ) {
131
+ isExtendedIterationCacheEnabled = isEnabled
132
+ }
133
+
127
134
/// Load an iteration from disk, or create a suitable starting value if such a file does not exist.
128
- private func loadIteration( for iterationID: SnapshotIterationIdentifier ) throws -> SnapshotIteration {
135
+ func loadIteration( for iterationID: SnapshotIterationIdentifier ? ) async throws -> SnapshotIteration ? {
136
+ guard let iterationID else { return nil }
137
+ if let iteration = cachedIterations [ iterationID] {
138
+ return iteration
139
+ }
129
140
do {
130
141
let data = try Data ( contentsOf: iterationURL ( for: iterationID) )
131
142
132
143
let iteration = try JSONDecoder . shared. decode ( SnapshotIteration . self, from: data)
133
144
134
- cachedIteration = iteration
145
+ if !isExtendedIterationCacheEnabled {
146
+ cachedIterations. removeAll ( )
147
+ }
148
+ cachedIterations [ iteration. id] = iteration
135
149
return iteration
136
150
} catch {
137
151
throw error
@@ -155,7 +169,7 @@ extension Snapshot {
155
169
cachedManifest = manifest
156
170
}
157
171
158
- /// Write the specified iteration to the store, and cache the results in ``Snapshot/cachedIteration ``.
172
+ /// Write the specified iteration to the store, and cache the results in ``Snapshot/cachedIterations ``.
159
173
private func write( iteration: SnapshotIteration ) throws where AccessMode == ReadWrite {
160
174
let iterationURL = iterationURL ( for: iteration. id)
161
175
/// Make sure the directories exists first.
@@ -166,7 +180,10 @@ extension Snapshot {
166
180
try data. write ( to: iterationURL, options: . atomic)
167
181
168
182
/// Update the cache since we know what it should be.
169
- cachedIteration = iteration
183
+ if !isExtendedIterationCacheEnabled {
184
+ cachedIterations. removeAll ( )
185
+ }
186
+ cachedIterations [ iteration. id] = iteration
170
187
}
171
188
172
189
/// Load and update the manifest in an updater, returning the task for the updater.
@@ -200,26 +217,19 @@ extension Snapshot {
200
217
201
218
/// Load the manifest so we have a fresh copy, unless we have a cached copy already.
202
219
var manifest = try cachedManifest ?? self . loadManifest ( )
203
- var iteration : SnapshotIteration
204
- if let cachedIteration, cachedIteration. id == manifest. currentIteration {
205
- iteration = cachedIteration
206
- } else if let iterationID = manifest. currentIteration {
207
- iteration = try self . loadIteration ( for: iterationID)
208
- } else {
209
- let date = Date ( )
210
- iteration = SnapshotIteration ( id: SnapshotIterationIdentifier ( date: date) , creationDate: date)
211
- }
220
+ let precedingIteration = try await self . loadIteration ( for: manifest. currentIteration)
221
+ var iteration = precedingIteration ?? SnapshotIteration ( )
212
222
213
223
/// Let the updater do something with the manifest, storing the variable on the Task Local stack.
214
224
let returnValue = try await SnapshotTaskLocals . $manifest. withValue ( ( manifest, iteration) ) {
215
225
try await updater ( & manifest, & iteration)
216
226
}
217
227
218
228
/// Only write to the store if we changed the manifest for any reason
219
- if iteration. isMeaningfullyChanged ( from: cachedIteration ) {
229
+ if iteration. isMeaningfullyChanged ( from: precedingIteration ) {
220
230
iteration. creationDate = Date ( )
221
231
iteration. id = SnapshotIterationIdentifier ( date: iteration. creationDate)
222
- iteration. precedingIteration = cachedIteration ? . id
232
+ iteration. precedingIteration = precedingIteration ? . id
223
233
224
234
try write ( iteration: iteration)
225
235
}
@@ -260,15 +270,7 @@ extension Snapshot {
260
270
261
271
/// Load the manifest so we have a fresh copy, unless we have a cached copy already.
262
272
let manifest = try cachedManifest ?? self . loadManifest ( )
263
- var iteration : SnapshotIteration
264
- if let cachedIteration, cachedIteration. id == manifest. currentIteration {
265
- iteration = cachedIteration
266
- } else if let iterationID = manifest. currentIteration {
267
- iteration = try self . loadIteration ( for: iterationID)
268
- } else {
269
- let date = Date ( )
270
- iteration = SnapshotIteration ( id: SnapshotIterationIdentifier ( date: date) , creationDate: date)
271
- }
273
+ let iteration = try await self . loadIteration ( for: manifest. currentIteration) ?? SnapshotIteration ( )
272
274
273
275
/// Let the accessor do something with the manifest, storing the variable on the Task Local stack.
274
276
return try await SnapshotTaskLocals . $manifest. withValue ( ( manifest, iteration) ) {
0 commit comments