Skip to content

Commit

Permalink
Added choice for synchronous mode.
Browse files Browse the repository at this point in the history
  • Loading branch information
liuliu committed Jun 28, 2020
1 parent f8f301d commit 7df4078
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
<attribute name="tag" optional="YES" attributeType="String"/>
<attribute name="text" optional="YES" attributeType="String"/>
<attribute name="title" optional="YES" attributeType="String"/>
<fetchIndex name="titleIndex">
<fetchIndexElement property="title" type="Binary" order="ascending"/>
</fetchIndex>
</entity>
<elements>
<element name="BenchDoc" positionX="-63" positionY="-18" width="128" height="178"/>
Expand Down
123 changes: 119 additions & 4 deletions app/Benchmarks/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,73 @@ final class BenchmarksViewController: UIViewController {
persistentContainer.performBackgroundTask { (objectContext) in
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "BenchDoc")
let allDocs = try! objectContext.fetch(fetchRequest)
for i in allDocs {
i.setValue(11, forKeyPath: "priority")
for (i, doc) in allDocs.enumerated() {
doc.setValue("tag\(i + 1)", forKeyPath: "tag")
doc.setValue(11, forKeyPath: "priority")
doc.setValue(1, forKeyPath: "pos_x")
doc.setValue(2, forKeyPath: "pos_y")
doc.setValue(3, forKeyPath: "pos_z")
switch i % 3 {
case 1:
doc.setValue(1, forKeyPath: "color")
doc.setValue(["image\(i)"], forKeyPath: "images")
case 2:
doc.setValue(0, forKeyPath: "color")
case 0:
doc.setValue(2, forKeyPath: "color")
doc.setValue("text\(i)", forKeyPath: "text")
default:
break
}
}
try! objectContext.save()
updateEndTime = CACurrentMediaTime()
updateGroup.leave()
}
updateGroup.wait()
stats += "Update \(Self.NumberOfEntities): \(updateEndTime - updateStartTime) sec\n"
let individualUpdateGroup = DispatchGroup()
individualUpdateGroup.enter()
let individualUpdateStartTime = CACurrentMediaTime()
var individualUpdateEndTime = individualUpdateStartTime
persistentContainer.performBackgroundTask { (objectContext) in
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "BenchDoc")
let allDocs = try! objectContext.fetch(fetchRequest)
for (i, doc) in allDocs.enumerated() {
doc.setValue("tag\(i + 2)", forKeyPath: "tag")
doc.setValue(12, forKeyPath: "priority")
doc.setValue(3, forKeyPath: "pos_x")
doc.setValue(2, forKeyPath: "pos_y")
doc.setValue(1, forKeyPath: "pos_z")
switch i % 3 {
case 2:
doc.setValue(1, forKeyPath: "color")
doc.setValue(["image\(i)"], forKeyPath: "images")
case 0:
doc.setValue(0, forKeyPath: "color")
case 1:
doc.setValue(2, forKeyPath: "color")
doc.setValue("text\(i)", forKeyPath: "text")
default:
break
}
try! objectContext.save()
}
individualUpdateEndTime = CACurrentMediaTime()
individualUpdateGroup.leave()
}
individualUpdateGroup.wait()
stats += "Update \(Self.NumberOfEntities) Individually: \(individualUpdateEndTime - individualUpdateStartTime) sec\n"
let individualFetchRequest = NSFetchRequest<NSManagedObject>(entityName: "BenchDoc")
let individualFetchStartTime = CACurrentMediaTime()
var newAllDocs = [NSManagedObject]()
for i in 0..<Self.NumberOfEntities {
individualFetchRequest.predicate = NSPredicate(format: "title = %@", argumentArray: ["title\(i)"])
let docs = try! persistentContainer.viewContext.fetch(individualFetchRequest)
newAllDocs.append(docs[0])
}
let individualFetchEndTime = CACurrentMediaTime()
stats += "Fetched \(newAllDocs.count) objects individually with \(individualFetchEndTime - individualFetchStartTime) sec\n"
let deleteGroup = DispatchGroup()
deleteGroup.enter()
let deleteStartTime = CACurrentMediaTime()
Expand Down Expand Up @@ -149,6 +207,8 @@ final class BenchmarksViewController: UIViewController {
for i: Int32 in 0..<Int32(Self.NumberOfEntities) {
let creationRequest = BenchDocChangeRequest.creationRequest()
creationRequest.title = "title\(i)"
creationRequest.tag = "tag\(i)"
creationRequest.pos = Vec3()
switch i % 3 {
case 0:
creationRequest.color = .blue
Expand Down Expand Up @@ -187,9 +247,23 @@ final class BenchmarksViewController: UIViewController {
dflat.performChanges([BenchDoc.self], changesHandler: { [weak self] (txnContext) in
guard let self = self else { return }
let allDocs = self.dflat.fetchFor(BenchDoc.self).all()
for i in allDocs {
guard let changeRequest = BenchDocChangeRequest.changeRequest(i) else { continue }
for (i, doc) in allDocs.enumerated() {
guard let changeRequest = BenchDocChangeRequest.changeRequest(doc) else { continue }
changeRequest.tag = "tag\(i + 1)"
changeRequest.priority = 11
changeRequest.pos = Vec3(x: 1, y: 2, z: 3)
switch i % 3 {
case 1:
changeRequest.color = .blue
changeRequest.content = .imageContent(ImageContent(images: ["image\(i)"]))
case 2:
changeRequest.color = .red
case 0:
changeRequest.color = .green
changeRequest.content = .textContent(TextContent(text: "text\(i)"))
default:
break
}
txnContext.try(submit: changeRequest)
}
}) { (succeed) in
Expand All @@ -198,6 +272,47 @@ final class BenchmarksViewController: UIViewController {
}
updateGroup.wait()
stats += "Update \(Self.NumberOfEntities): \(updateEndTime - updateStartTime) sec\n"
let allDocs = self.dflat.fetchFor(BenchDoc.self).all()
let individualUpdateGroup = DispatchGroup()
individualUpdateGroup.enter()
let individualUpdateStartTime = CACurrentMediaTime()
var individualUpdateEndTime = individualUpdateStartTime
for (i, doc) in allDocs.enumerated() {
dflat.performChanges([BenchDoc.self], changesHandler: { (txnContext) in
guard let changeRequest = BenchDocChangeRequest.changeRequest(doc) else { return }
changeRequest.tag = "tag\(i + 2)"
changeRequest.priority = 12
changeRequest.pos = Vec3(x: 3, y: 2, z: 1)
switch i % 3 {
case 2:
changeRequest.color = .blue
changeRequest.content = .imageContent(ImageContent(images: ["image\(i)"]))
case 0:
changeRequest.color = .red
case 1:
changeRequest.color = .green
changeRequest.content = .textContent(TextContent(text: "text\(i)"))
default:
break
}
txnContext.try(submit: changeRequest)
}) { (succeed) in
if i == allDocs.count - 1 {
individualUpdateEndTime = CACurrentMediaTime()
individualUpdateGroup.leave()
}
}
}
individualUpdateGroup.wait()
stats += "Update \(Self.NumberOfEntities) Individually: \(individualUpdateEndTime - individualUpdateStartTime) sec\n"
let individualFetchStartTime = CACurrentMediaTime()
var newAllDocs = [BenchDoc]()
for i in 0..<Self.NumberOfEntities {
let docs = dflat.fetchFor(BenchDoc.self).where(BenchDoc.title == "title\(i)")
newAllDocs.append(docs[0])
}
let individualFetchEndTime = CACurrentMediaTime()
stats += "Fetched \(newAllDocs.count) objects individually with \(individualFetchEndTime - individualFetchStartTime) sec\n"
let deleteGroup = DispatchGroup()
deleteGroup.enter()
let deleteStartTime = CACurrentMediaTime()
Expand Down
14 changes: 13 additions & 1 deletion src/sqlite/SQLiteWorkspace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,26 @@ public final class SQLiteWorkspace: Workspace {
case concurrent
case serial
}
public enum Synchronous {
case normal
case full
}
private static let RebuildIndexDelayOnDiskFull = 5.0 // In seconds..
private static let RebuildIndexBatchLimit = 500 // We can jam the write queue by just having index rebuild (upon upgrade). This limits that each rebuild batches at this limit, if the limit exceed, we will dispatch back to the queue again to finish up.
private let filePath: String
private let fileProtectionLevel: FileProtectionLevel
private let targetQueue: DispatchQueue
private let readerPool: SQLiteConnectionPool
private let synchronous: Synchronous
private let writeConcurrency: WriteConcurrency
private var writer: SQLiteConnection?
private var tableSpaces = [ObjectIdentifier: SQLiteTableSpace]()
private let state = SQLiteWorkspaceState()

public required init(filePath: String, fileProtectionLevel: FileProtectionLevel, writeConcurrency: WriteConcurrency = .concurrent, targetQueue: DispatchQueue = DispatchQueue(label: "dflat.workq", qos: .utility, attributes: .concurrent)) {
public required init(filePath: String, fileProtectionLevel: FileProtectionLevel, synchronous: Synchronous = .normal, writeConcurrency: WriteConcurrency = .concurrent, targetQueue: DispatchQueue = DispatchQueue(label: "dflat.workq", qos: .utility, attributes: .concurrent)) {
self.filePath = filePath
self.fileProtectionLevel = fileProtectionLevel
self.synchronous = synchronous
self.writeConcurrency = writeConcurrency
self.targetQueue = targetQueue
self.readerPool = SQLiteConnectionPool(capacity: 64, filePath: filePath)
Expand Down Expand Up @@ -376,6 +382,12 @@ public final class SQLiteWorkspace: Workspace {
guard let writer = SQLiteConnection(filePath: filePath, createIfMissing: true, readOnly: false) else { return nil }
sqlite3_busy_timeout(writer.sqlite, 10_000)
sqlite3_exec(writer.sqlite, "PRAGMA journal_mode=WAL", nil, nil, nil)
switch synchronous {
case .normal:
sqlite3_exec(writer.sqlite, "PRAGMA synchronous=NORMAL", nil, nil, nil)
case .full:
sqlite3_exec(writer.sqlite, "PRAGMA synchronous=FULL", nil, nil, nil)
}
sqlite3_exec(writer.sqlite, "PRAGMA auto_vacuum=incremental", nil, nil, nil)
sqlite3_exec(writer.sqlite, "PRAGMA incremental_vaccum(2)", nil, nil, nil)
self.writer = writer
Expand Down

0 comments on commit 7df4078

Please sign in to comment.