Swiftgram/submodules/Postbox/Sources/ReverseAssociatedPeerTable.swift
2019-11-01 17:11:12 +04:00

100 lines
3.3 KiB
Swift

import Foundation
private func readPeerIds(_ buffer: ReadBuffer) -> Set<PeerId> {
assert(buffer.length % 8 == 0)
let count = buffer.length / 8
var result = Set<PeerId>()
for _ in 0 ..< count {
var value: Int64 = 0
buffer.read(&value, offset: 0, length: 8)
result.insert(PeerId(value))
}
return result
}
private func writePeerIds(_ buffer: WriteBuffer, _ peerIds: Set<PeerId>) {
for id in peerIds {
var value: Int64 = id.toInt64()
buffer.write(&value, offset: 0, length: 8)
}
}
final class ReverseAssociatedPeerTable: Table {
static func tableSpec(_ id: Int32) -> ValueBoxTable {
return ValueBoxTable(id: id, keyType: .int64, compactValuesOnCreation: false)
}
private let sharedKey = ValueBoxKey(length: 8)
private var cachedAssociations: [PeerId: Set<PeerId>] = [:]
private var updatedAssociations = Set<PeerId>()
private func key(_ peerId: PeerId) -> ValueBoxKey {
self.sharedKey.setInt64(0, value: peerId.toInt64())
return self.sharedKey
}
func get(peerId: PeerId) -> Set<PeerId> {
if let cached = self.cachedAssociations[peerId] {
return cached
} else {
if let value = self.valueBox.get(self.table, key: self.key(peerId)) {
let peerIds = readPeerIds(value)
self.cachedAssociations[peerId] = peerIds
return peerIds
} else {
self.cachedAssociations[peerId] = Set()
return Set()
}
}
}
func addReverseAssociation(target targetPeerId: PeerId, from sourcePeerId: PeerId) {
var value = self.get(peerId: targetPeerId)
if value.contains(sourcePeerId) {
assertionFailure()
} else {
value.insert(sourcePeerId)
self.cachedAssociations[targetPeerId] = value
self.updatedAssociations.insert(targetPeerId)
}
}
func removeReverseAssociation(target targetPeerId: PeerId, from sourcePeerId: PeerId) {
var value = self.get(peerId: targetPeerId)
if !value.contains(sourcePeerId) {
assertionFailure()
} else {
value.remove(sourcePeerId)
self.cachedAssociations[targetPeerId] = value
self.updatedAssociations.insert(targetPeerId)
}
}
override func clearMemoryCache() {
self.cachedAssociations.removeAll()
assert(self.updatedAssociations.isEmpty)
}
override func beforeCommit() {
if !self.updatedAssociations.isEmpty {
let buffer = WriteBuffer()
for peerId in self.updatedAssociations {
if let peerIds = self.cachedAssociations[peerId] {
if peerIds.isEmpty {
self.valueBox.remove(self.table, key: self.key(peerId), secure: false)
} else {
buffer.reset()
writePeerIds(buffer, peerIds)
self.valueBox.set(self.table, key: self.key(peerId), value: buffer)
}
} else {
assertionFailure()
}
}
self.updatedAssociations.removeAll()
}
}
}