Skip to content

Commit 67e558d

Browse files
committed
Bug fix in WorkspaceDictionary
1. Fix issue with keys where older keys may return. 2. Fix issue with removeAll where it may not update because the cache is empty.
1 parent 122ded4 commit 67e558d

File tree

2 files changed

+39
-6
lines changed

2 files changed

+39
-6
lines changed

src/sqlite/SQLiteWorkspaceDictionary.swift

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -469,28 +469,47 @@ struct SQLiteWorkspaceDictionary: WorkspaceDictionary {
469469
for i in 0..<Storage.size {
470470
storage.lock(i)
471471
defer { storage.unlock(i) }
472-
keys.formUnion(
473-
storage.dictionaries[i].compactMap { (key, value) -> String? in
474-
guard !(value is None) else { return nil }
475-
return key
476-
})
472+
for (key, value) in storage.dictionaries[i] {
473+
// Remove it, it doesn't exist any more from disk.
474+
if value is None {
475+
keys.remove(key)
476+
} else {
477+
keys.insert(key)
478+
}
479+
}
477480
}
478481
return Array(keys)
479482
}
480483

481484
func removeAll() {
485+
let namespace = storage.namespace
486+
let items = workspace.fetch(for: DictItem.self).where(DictItem.namespace == namespace)
487+
var keys = [[String]](repeating: [], count: Storage.size)
488+
for key in items.lazy.map(\.key) {
489+
var hasher = Hasher()
490+
key.hash(into: &hasher)
491+
let hashValue = Int(UInt(bitPattern: hasher.finalize()) % UInt(Storage.size))
492+
keys[hashValue].append(key)
493+
}
482494
for i in 0..<Storage.size {
483495
storage.lock(i)
484496
defer { storage.unlock(i) }
497+
// Set existing ones in the dictionaries to be None.
485498
for key in storage.dictionaries[i].keys {
486499
storage.dictionaries[i][key] = None.none
487500
}
501+
// Set the ones fetched from disk to be None.
502+
for key in keys[i] {
503+
storage.dictionaries[i][key] = None.none
504+
}
488505
}
489506
let workspace = self.workspace
490-
let namespace = storage.namespace
491507
workspace.performChanges(
492508
[DictItem.self],
493509
changesHandler: { txnContext in
510+
// Note that any insertions / updates after removeAll will be queued after this.
511+
// We need to fetch again because we may have pending writes that not available
512+
// when do the fetching in the beginning of removeAll.
494513
let items = workspace.fetch(for: DictItem.self).where(DictItem.namespace == namespace)
495514
for item in items {
496515
if let deletionRequest = DictItemChangeRequest.deletionRequest(item) {

src/tests/DictionaryTests.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,19 @@ class DictionaryTests: XCTestCase {
208208
XCTAssertEqual(newDictionary["intValue", default: 9], 9)
209209
}
210210

211+
func testRemoveAllWithPersistence() {
212+
guard var dictionary = dflat?.dictionary else { return }
213+
dictionary["stringValue"] = "abcde"
214+
dictionary["intValue", Int.self] = 10
215+
dictionary["doubleValue", Double.self] = 12.3
216+
dictionary.synchronize()
217+
let newDflat = SQLiteWorkspace(filePath: filePath!, fileProtectionLevel: .noProtection)
218+
var newDictionary = newDflat.dictionary
219+
newDictionary.removeAll()
220+
let keys = newDictionary.keys
221+
XCTAssertEqual(keys.count, 0)
222+
}
223+
211224
static let allTests = [
212225
("testReadWriteReadCodableObject", testReadWriteReadCodableObject),
213226
("testReadWriteReadFlatBuffersObject", testReadWriteReadFlatBuffersObject),
@@ -223,5 +236,6 @@ class DictionaryTests: XCTestCase {
223236
("testReadWriteReadString", testReadWriteReadString),
224237
("testIterateKeys", testIterateKeys),
225238
("testRemoveAll", testRemoveAll),
239+
("testRemoveAllWithPersistence", testRemoveAllWithPersistence),
226240
]
227241
}

0 commit comments

Comments
 (0)