Merge pull request #200 from loki-project/performance

Further Performance Improvements
This commit is contained in:
Niels Andriesse 2020-06-01 11:08:26 +10:00 committed by GitHub
commit c2c750baaf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 65 additions and 3 deletions

View file

@ -14,13 +14,20 @@ public extension LokiAPI {
internal static let snodeFailureThreshold = 2
// MARK: Caching
internal static var swarmCache: [String:[LokiAPITarget]] = [:]
internal static var swarmCache: [String:[LokiAPITarget]] = [:] // TODO: Make this set based?
internal static func dropSnodeFromSwarmIfNeeded(_ target: LokiAPITarget, hexEncodedPublicKey: String) {
let swarm = LokiAPI.swarmCache[hexEncodedPublicKey]
if var swarm = swarm, let index = swarm.firstIndex(of: target) {
swarm.remove(at: index)
LokiAPI.swarmCache[hexEncodedPublicKey] = swarm
// Dispatch async on the main queue to avoid nested write transactions
DispatchQueue.main.async {
let storage = OWSPrimaryStorage.shared()
storage.dbReadWriteConnection.readWrite { transaction in
storage.setSwarm(swarm, for: hexEncodedPublicKey, in: transaction)
}
}
}
}
@ -96,11 +103,30 @@ public extension LokiAPI {
}
internal static func getSwarm(for hexEncodedPublicKey: String) -> Promise<[LokiAPITarget]> {
if swarmCache[hexEncodedPublicKey] == nil {
storage.dbReadConnection.read { transaction in
swarmCache[hexEncodedPublicKey] = storage.getSwarm(for: hexEncodedPublicKey, in: transaction)
}
}
if let cachedSwarm = swarmCache[hexEncodedPublicKey], cachedSwarm.count >= minimumSwarmSnodeCount {
return Promise<[LokiAPITarget]> { $0.fulfill(cachedSwarm) }
} else {
print("[Loki] Getting swarm for: \(hexEncodedPublicKey).")
let parameters: [String:Any] = [ "pubKey" : hexEncodedPublicKey ]
return getRandomSnode().then(on: workQueue) { invoke(.getSwarm, on: $0, associatedWith: hexEncodedPublicKey, parameters: parameters) }.map { parseTargets(from: $0) }.get { swarmCache[hexEncodedPublicKey] = $0 }
return getRandomSnode().then(on: workQueue) {
invoke(.getSwarm, on: $0, associatedWith: hexEncodedPublicKey, parameters: parameters)
}.map {
parseTargets(from: $0)
}.get { swarm in
swarmCache[hexEncodedPublicKey] = swarm
// Dispatch async on the main queue to avoid nested write transactions
DispatchQueue.main.async {
let storage = OWSPrimaryStorage.shared()
storage.dbReadWriteConnection.readWrite { transaction in
storage.setSwarm(swarm, for: hexEncodedPublicKey, in: transaction)
}
}
}
}
}

View file

@ -1,4 +1,6 @@
public typealias Snode = LokiAPITarget
/// Either a service node or another client if P2P is enabled.
public final class LokiAPITarget : NSObject, NSCoding {
internal let address: String

View file

@ -49,7 +49,7 @@ public struct LokiMessage {
/// - Returns: The promise of a new message with its `timestamp` and `nonce` set.
public func calculatePoW() -> Promise<LokiMessage> {
return Promise<LokiMessage> { seal in
DispatchQueue.global().async {
DispatchQueue.global(qos: .userInitiated).async {
let now = NSDate.ows_millisecondTimeStamp()
let dataAsString = self.data as! String // Safe because of how from(signalMessage:with:) is implemented
if let nonce = ProofOfWork.calculate(data: dataAsString, pubKey: self.destination, timestamp: now, ttl: self.ttl) {

View file

@ -1,4 +1,6 @@
// TODO: Make this strongly typed like LKUserDefaults
public extension OWSPrimaryStorage {
// MARK: - Snode Pool
@ -30,6 +32,37 @@ public extension OWSPrimaryStorage {
// MARK: - Swarm
private func getSwarmCollection(for publicKey: String) -> String {
return "LokiSwarmCollection-\(publicKey)"
}
public func setSwarm(_ swarm: [Snode], for publicKey: String, in transaction: YapDatabaseReadWriteTransaction) {
print("[Loki] Caching swarm for: \(publicKey).")
clearSwarm(for: publicKey, in: transaction)
let collection = getSwarmCollection(for: publicKey)
swarm.forEach { snode in
transaction.setObject(snode, forKey: snode.description, inCollection: collection)
}
}
public func clearSwarm(for publicKey: String, in transaction: YapDatabaseReadWriteTransaction) {
let collection = getSwarmCollection(for: publicKey)
transaction.removeAllObjects(inCollection: collection)
}
public func getSwarm(for publicKey: String, in transaction: YapDatabaseReadTransaction) -> [Snode] {
var result: [Snode] = []
let collection = getSwarmCollection(for: publicKey)
transaction.enumerateKeysAndObjects(inCollection: collection) { _, object, _ in
guard let snode = object as? Snode else { return }
result.append(snode)
}
return result
}
// MARK: - Onion Request Path
private static let onionRequestPathCollection = "LokiOnionRequestPathCollection"

View file

@ -131,6 +131,7 @@ public class MessageSenderJobQueue: NSObject, JobQueue {
let operationQueue = OperationQueue()
operationQueue.name = "DefaultSendingQueue"
operationQueue.maxConcurrentOperationCount = 1
operationQueue.qualityOfService = .userInitiated
return operationQueue
}()