diff --git a/Postbox/Coding.swift b/Postbox/Coding.swift index 864a6449fa..55c423660e 100644 --- a/Postbox/Coding.swift +++ b/Postbox/Coding.swift @@ -479,6 +479,17 @@ public final class Decoder { } } + public func decodeInt32ForKey(key: UnsafePointer) -> Int32? { + if Decoder.positionOnKey(UnsafePointer(self.buffer.memory), offset: &self.buffer.offset, maxOffset: self.buffer.length, length: self.buffer.length, key: key, valueType: .Int32) { + var value: Int32 = 0 + memcpy(&value, self.buffer.memory + self.buffer.offset, 4) + self.buffer.offset += 4 + return value + } else { + return nil + } + } + public func decodeInt64ForKey(key: UnsafePointer) -> Int64 { if Decoder.positionOnKey(UnsafePointer(self.buffer.memory), offset: &self.buffer.offset, maxOffset: self.buffer.length, length: self.buffer.length, key: key, valueType: .Int64) { var value: Int64 = 0 diff --git a/Postbox/Media.swift b/Postbox/Media.swift index a4f54c2540..5b53c468b2 100644 --- a/Postbox/Media.swift +++ b/Postbox/Media.swift @@ -9,7 +9,7 @@ public struct MediaId: Hashable, CustomStringConvertible { public var hashValue: Int { get { - return Int(self.id) + return Int((self.id & 0xffffffff) ^ ((self.id >> 32) & 0xffffffff)) } } diff --git a/Postbox/Message.swift b/Postbox/Message.swift index a2b25de31e..62e0829108 100644 --- a/Postbox/Message.swift +++ b/Postbox/Message.swift @@ -27,14 +27,20 @@ public struct MessageId: Hashable, CustomStringConvertible { } public init(_ buffer: ReadBuffer) { - self.peerId = PeerId(namespace: 0, id: 0) - self.namespace = 0 - self.id = 0 - memcpy(&self.peerId.namespace, buffer.memory + buffer.offset, 4) - memcpy(&self.peerId.id, buffer.memory + (buffer.offset + 4), 4) - memcpy(&self.namespace, buffer.memory + (buffer.offset + 8), 4) - memcpy(&self.id, buffer.memory + (buffer.offset + 12), 4) + var peerIdNamespaceValue: Int32 = 0 + memcpy(&peerIdNamespaceValue, buffer.memory + buffer.offset, 4) + var peerIdIdValue: Int32 = 0 + memcpy(&peerIdIdValue, buffer.memory + (buffer.offset + 4), 4) + self.peerId = PeerId(namespace: peerIdNamespaceValue, id: peerIdIdValue) + + var namespaceValue: Int32 = 0 + memcpy(&namespaceValue, buffer.memory + (buffer.offset + 8), 4) + self.namespace = namespaceValue + var idValue: Int32 = 0 + memcpy(&idValue, buffer.memory + (buffer.offset + 12), 4) + self.id = idValue + buffer.offset += 16 } @@ -114,7 +120,7 @@ public protocol Message: Coding { var peerIds: [PeerId] { get } } -public struct RenderedMessage { +public struct RenderedMessage: Equatable, Comparable { public let message: Message internal let incomplete: Bool @@ -135,3 +141,11 @@ public struct RenderedMessage { self.incomplete = false } } + +public func ==(lhs: RenderedMessage, rhs: RenderedMessage) -> Bool { + return lhs.message.id == rhs.message.id +} + +public func <(lhs: RenderedMessage, rhs: RenderedMessage) -> Bool { + return MessageIndex(lhs.message) < MessageIndex(rhs.message) +} diff --git a/Postbox/MessageView.swift b/Postbox/MessageView.swift index 3050f7cf2a..aea71cd29b 100644 --- a/Postbox/MessageView.swift +++ b/Postbox/MessageView.swift @@ -59,9 +59,10 @@ public final class MutableMessageView: CustomStringConvertible { } else { self.earlier[message.message.id.namespace] = message } + return true + } else { + return false } - - return true } else if index > first { if next != nil && index > next! { let laterMessage = self.later[message.message.id.namespace] @@ -71,6 +72,9 @@ public final class MutableMessageView: CustomStringConvertible { } else { self.later[message.message.id.namespace] = message } + return true + } else { + return false } } else { self.messages.append(message) @@ -79,8 +83,8 @@ public final class MutableMessageView: CustomStringConvertible { self.earlier[earliest.message.id.namespace] = earliest self.messages.removeAtIndex(0) } + return true } - return true } else if index != last && index != first { var i = self.messages.count while i >= 1 { diff --git a/Postbox/Peer.swift b/Postbox/Peer.swift index 03ca43228a..a6f7fac52c 100644 --- a/Postbox/Peer.swift +++ b/Postbox/Peer.swift @@ -36,6 +36,7 @@ public struct PeerId: Hashable, CustomStringConvertible, Comparable { buffer.offset += 4 var i = 0 var array: [PeerId] = [] + array.reserveCapacity(Int(length)) while i < Int(length) { var value: Int64 = 0 buffer.read(&value, offset: 0, length: 8) diff --git a/Postbox/PeerView.swift b/Postbox/PeerView.swift index 82085302e8..74b96c743f 100644 --- a/Postbox/PeerView.swift +++ b/Postbox/PeerView.swift @@ -1,27 +1,53 @@ import Foundation -public final class PeerViewEntry { +public final class PeerViewEntry: Equatable, Comparable { public let peerId: PeerId public let peer: Peer? - public let message: RenderedMessage + public let messageIndex: MessageIndex + public let message: RenderedMessage? public init(peer: Peer, message: RenderedMessage) { self.peerId = peer.id self.peer = peer self.message = message + self.messageIndex = MessageIndex(message.message) } public init(peerId: PeerId, message: RenderedMessage) { self.peerId = peerId self.peer = nil self.message = message + self.messageIndex = MessageIndex(message.message) } private init(peer: Peer?, peerId: PeerId, message: RenderedMessage) { self.peer = peer self.peerId = peerId self.message = message + self.messageIndex = MessageIndex(message.message) } + + private init(peer: Peer?, peerId: PeerId, message: RenderedMessage?, messageIndex: MessageIndex) { + self.peer = peer + self.peerId = peerId + self.message = message + self.messageIndex = messageIndex + } + + init(peer: Peer?, peerId: PeerId, messageIndex: MessageIndex) { + self.peer = peer + self.peerId = peerId + self.messageIndex = messageIndex + self.message = nil + } +} + +public func ==(lhs: PeerViewEntry, rhs: PeerViewEntry) -> Bool { + return PeerViewEntryIndex(lhs) == PeerViewEntryIndex(rhs) +} + +public func <(lhs: PeerViewEntry, rhs: PeerViewEntry) -> Bool { + return PeerViewEntryIndex(lhs) < PeerViewEntryIndex(rhs) } public struct PeerViewEntryIndex: Equatable, Comparable { @@ -30,7 +56,7 @@ public struct PeerViewEntryIndex: Equatable, Comparable { public init(_ entry: PeerViewEntry) { self.peerId = entry.peerId - self.messageIndex = MessageIndex(entry.message.message) + self.messageIndex = entry.messageIndex } public init(peerId: PeerId, messageIndex: MessageIndex) { @@ -263,14 +289,14 @@ public final class MutablePeerView: CustomStringConvertible { if let earlier = self.earlier { if let peer = peers[earlier.peerId] { - self.earlier = PeerViewEntry(peer: peer, message: earlier.message) + self.earlier = PeerViewEntry(peer: peer, peerId: earlier.peerId, message: earlier.message, messageIndex: earlier.messageIndex) updated = true } } if let later = self.later { if let peer = peers[later.peerId] { - self.later = PeerViewEntry(peer: peer, message: later.message) + self.later = PeerViewEntry(peer: peer, peerId: later.peerId, message: later.message, messageIndex: later.messageIndex) updated = true } } @@ -278,7 +304,8 @@ public final class MutablePeerView: CustomStringConvertible { var i = 0 while i < self.entries.count { if let peer = peers[self.entries[i].peerId] { - self.entries[i] = PeerViewEntry(peer: peer, message: self.entries[i].message) + let entry = self.entries[i] + self.entries[i] = PeerViewEntry(peer: peer, peerId: entry.peerId, message: entry.message, messageIndex: entry.messageIndex) updated = true } i++ @@ -291,19 +318,25 @@ public final class MutablePeerView: CustomStringConvertible { var result: [Message] = [] if let earlier = self.earlier { - if earlier.message.incomplete { - result.append(earlier.message.message) + if let message = earlier.message { + if message.incomplete { + result.append(message.message) + } } } if let later = self.later { - if later.message.incomplete { - result.append(later.message.message) + if let message = later.message { + if message.incomplete { + result.append(message.message) + } } } for entry in self.entries { - if entry.message.incomplete { - result.append(entry.message.message) + if let message = entry.message { + if message.incomplete { + result.append(message.message) + } } } @@ -312,20 +345,26 @@ public final class MutablePeerView: CustomStringConvertible { public func completeMessages(messages: [MessageId : RenderedMessage]) { if let earlier = self.earlier { - if let message = messages[earlier.message.message.id] { - self.earlier = PeerViewEntry(peer: earlier.peer, peerId: earlier.peerId, message: message) + if let earlierMessage = earlier.message { + if let message = messages[earlierMessage.message.id] { + self.earlier = PeerViewEntry(peer: earlier.peer, peerId: earlier.peerId, message: message) + } } } if let later = self.later { - if let message = messages[later.message.message.id] { - self.later = PeerViewEntry(peer: later.peer, peerId: later.peerId, message: message) + if let laterMessage = later.message { + if let message = messages[laterMessage.message.id] { + self.later = PeerViewEntry(peer: later.peer, peerId: later.peerId, message: message) + } } } var i = 0 while i < self.entries.count { - if let message = messages[self.entries[i].message.message.id] { - self.entries[i] = PeerViewEntry(peer: self.entries[i].peer, peerId: self.entries[i].peerId, message: message) + if let entryMessage = self.entries[i].message { + if let message = messages[entryMessage.message.id] { + self.entries[i] = PeerViewEntry(peer: self.entries[i].peer, peerId: self.entries[i].peerId, message: message) + } } i++ } @@ -336,7 +375,7 @@ public final class MutablePeerView: CustomStringConvertible { if let earlier = self.earlier { string += "more(" - string += "(p \(earlier.peerId.namespace):\(earlier.peerId.id), m \(earlier.message.message.id.namespace):\(earlier.message.message.id.id)—\(earlier.message.message.timestamp)" + string += "(p \(earlier.peerId.namespace):\(earlier.peerId.id), m \(earlier.message?.message.id.namespace ?? 0):\(earlier.message?.message.id.id ?? 0)—\(earlier.message?.message.timestamp ?? 0)" string += ") " } @@ -348,13 +387,13 @@ public final class MutablePeerView: CustomStringConvertible { } else { string += ", " } - string += "(p \(entry.peerId.namespace):\(entry.peerId.id), m \(entry.message.message.id.namespace):\(entry.message.message.id.id)—\(entry.message.message.timestamp))" + string += "(p \(entry.peerId.namespace):\(entry.peerId.id), m \(entry.message?.message.id.namespace ?? 0):\(entry.message?.message.id.id ?? 0)—\(entry.message?.message.timestamp ?? 0))" } string += "]" if let later = self.later { string += " more(" - string += "(p \(later.peerId.namespace):\(later.peerId), m \(later.message.message.id.namespace):\(later.message.message.id.id)—\(later.message.message.timestamp)" + string += "(p \(later.peerId.namespace):\(later.peerId), m \(later.message?.message.id.namespace ?? 0):\(later.message?.message.id.id ?? 0)—\(later.message?.message.timestamp ?? 0)" string += ")" } @@ -400,7 +439,7 @@ public final class PeerView: CustomStringConvertible { } else { string += ", " } - string += "(p \(entry.peerId.namespace):\(entry.peerId.id), m \(entry.message.message.id.namespace):\(entry.message.message.id.id)—\(entry.message.message.timestamp))" + string += "(p \(entry.peerId.namespace):\(entry.peerId.id), m \(entry.message?.message.id.namespace ?? 0):\(entry.message?.message.id.id ?? 0)—\(entry.message?.message.timestamp ?? 0))" } string += "]" diff --git a/Postbox/Postbox.swift b/Postbox/Postbox.swift index ab23743c6e..3e4aea8711 100644 --- a/Postbox/Postbox.swift +++ b/Postbox/Postbox.swift @@ -1,6 +1,6 @@ import Foundation - import SwiftSignalKit +import sqlcipher public protocol PostboxState: Coding { @@ -21,6 +21,13 @@ public final class Modifier { self.postbox?.deleteMessagesWithIds(ids) } + public func deleteMessagesWithAbsoluteIndexedIds(ids: [Int32]) { + if let postbox = self.postbox { + let messageIds = postbox.messageIdsForAbsoluteIndexedIds(ids) + postbox.deleteMessagesWithIds(messageIds) + } + } + public func getState() -> State? { return self.postbox?.getState() } @@ -32,11 +39,16 @@ public final class Modifier { public func updatePeers(peers: [Peer], update: (Peer, Peer) -> Peer) { self.postbox?.updatePeers(peers, update: update) } + + public func peersWithIds(ids: [PeerId]) -> [PeerId : Peer] { + return self.postbox?.peersWithIds(ids) ?? [:] + } } public final class Postbox { private let basePath: String private let messageNamespaces: [MessageId.Namespace] + private let absoluteIndexedMessageNamespaces: [MessageId.Namespace] private let queue = SwiftSignalKit.Queue() private var database: Database! @@ -48,9 +60,10 @@ public final class Postbox { private var statePipe: Pipe = Pipe() - public init(basePath: String, messageNamespaces: [MessageId.Namespace]) { + public init(basePath: String, messageNamespaces: [MessageId.Namespace], absoluteIndexedMessageNamespaces: [MessageId.Namespace]) { self.basePath = basePath self.messageNamespaces = messageNamespaces + self.absoluteIndexedMessageNamespaces = absoluteIndexedMessageNamespaces self.openDatabase() } @@ -62,10 +75,10 @@ public final class Postbox { try NSFileManager.defaultManager().createDirectoryAtPath(self.basePath, withIntermediateDirectories: true, attributes: nil) } catch _ { } - self.database = Database(self.basePath.stringByAppendingPathComponent("db")) + self.database = Database(self.basePath + "/db") let result = self.database.scalar("PRAGMA user_version") as! Int64 - let version: Int64 = 7 + let version: Int64 = 11 if result == version { print("(Postbox schema version \(result))") } else { @@ -77,7 +90,7 @@ public final class Postbox { } catch (_) { } - self.database = Database(self.basePath.stringByAppendingPathComponent("db")) + self.database = Database(self.basePath + "/db") } print("(Postbox creating schema)") self.createSchema() @@ -108,6 +121,9 @@ public final class Postbox { //peer_messages self.database.execute("CREATE TABLE peer_messages (peerId INTEGER, namespace INTEGER, id INTEGER, data BLOB, associatedMediaIds BLOB, timestamp INTEGER, PRIMARY KEY(peerId, namespace, id))") + //peer_absolute_indexed_message_ids + self.database.execute("CREATE TABLE peer_absolute_indexed_message_ids (id INTEGER PRIMARY KEY, completeId BLOB)") + //peer_media self.database.execute("CREATE TABLE peer_media (peerId INTEGER, mediaNamespace INTEGER, messageNamespace INTEGER, messageId INTEGER, PRIMARY KEY (peerId, mediaNamespace, messageNamespace, messageId))") self.database.execute("CREATE INDEX peer_media_peerId_messageNamespace_messageId ON peer_media (peerId, messageNamespace, messageId)") @@ -126,9 +142,7 @@ public final class Postbox { self.database.execute("CREATE TABLE peers (id INTEGER PRIMARY KEY, data BLOB)") } - private class func peerViewEntryIndexForBlob(blob: Blob) -> PeerViewEntryIndex { - let buffer = ReadBuffer(memory: UnsafeMutablePointer(blob.data.bytes), length: blob.data.length, freeWhenDone: false) - + private class func peerViewEntryIndexForBuffer(buffer: ReadBuffer) -> PeerViewEntryIndex { var timestamp: Int32 = 0 buffer.read(×tamp, offset: 0, length: 4) timestamp = Int32(bigEndian: timestamp) @@ -373,6 +387,9 @@ public final class Postbox { let encoder = Encoder() encoder.encodeRootObject(state) + + + let blob = Blob(data: encoder.makeData()) self.database.prepareCached("INSERT OR REPLACE INTO state (id, data) VALUES (?, ?)").run(Int64(0), blob) @@ -444,6 +461,7 @@ public final class Postbox { private func addMessages(messages: [Message], medias: [Media]) { let messageInsertStatement = self.database.prepareCached("INSERT INTO peer_messages (peerId, namespace, id, data, associatedMediaIds, timestamp) VALUES (?, ?, ?, ?, ?, ?)") + let absoluteMessageIdsInsertStatement = self.database.prepareCached("INSERT INTO peer_absolute_indexed_message_ids (id, completeId) VALUES (?, ?)") let peerMediaInsertStatement = self.database.prepareCached("INSERT INTO peer_media (peerId, mediaNamespace, messageNamespace, messageId) VALUES (?, ?, ?, ?)") let mediaInsertStatement = self.database.prepareCached("INSERT INTO media (namespace, id, data, associatedMessageIds) VALUES (?, ?, ?, ?)") let referencedMessageIdsStatement = self.database.prepareCached("SELECT associatedMessageIds FROM media WHERE namespace = ? AND id = ?") @@ -486,6 +504,13 @@ public final class Postbox { } } + let completeIdData = NSMutableData(capacity: 8 + 4 + 4)! + var zero: Int64 = 0 + completeIdData.appendBytes(&zero, length: 8) + completeIdData.appendBytes(&zero, length: 8) + let completeIdDataMutableBytes = completeIdData.mutableBytes + let completeIdBlob = Blob(data: completeIdData) + for message in peerMessages { if existingMessageIds.contains(message.id) { continue @@ -512,6 +537,16 @@ public final class Postbox { messageInsertStatement.run(peerId.toInt64(), Int64(message.id.namespace), Int64(message.id.id), messageBlob, referencedMediaIdsMediaIdsBlob, Int64(message.timestamp)) + if self.absoluteIndexedMessageNamespaces.contains(message.id.namespace) { + var peerIdValue = peerId.toInt64() + memcpy(completeIdDataMutableBytes, &peerIdValue, 8) + var messageIdNamespaceValue: Int32 = message.id.namespace + memcpy(completeIdDataMutableBytes + 8, &messageIdNamespaceValue, 4) + var messageIdIdValue: Int32 = message.id.id + memcpy(completeIdDataMutableBytes + 12, &messageIdIdValue, 4) + absoluteMessageIdsInsertStatement.run(Int64(message.id.id), completeIdBlob) + } + for id in message.mediaIds { peerMediaInsertStatement.run(peerId.toInt64(), Int64(id.namespace), Int64(message.id.namespace), Int64(message.id.id)) } @@ -649,7 +684,7 @@ public final class Postbox { for id in ids { for row in select.run(Int64(id.namespace), id.id) { let blob = row[0] as! Blob - if let media = Decoder(buffer: ReadBuffer(memory: UnsafeMutablePointer(blob.data.bytes), length: blob.data.length, freeWhenDone: false)) as? Media { + if let media = Decoder(buffer: ReadBuffer(memory: UnsafeMutablePointer(blob.data.bytes), length: blob.data.length, freeWhenDone: false)).decodeRootObject() as? Media { result[media.id] = media } break @@ -802,7 +837,8 @@ public final class Postbox { private func updatePeerEntry(peerId: PeerId, message: RenderedMessage?, replace: Bool = false) { var currentIndex: PeerViewEntryIndex? for row in self.database.prepareCached("SELECT entry FROM peer_entries WHERE peerId = ?").run(peerId.toInt64()) { - currentIndex = Postbox.peerViewEntryIndexForBlob(row[0] as! Blob) + let blob = row[0] as! Blob + currentIndex = Postbox.peerViewEntryIndexForBuffer(ReadBuffer(memory: UnsafeMutablePointer(blob.data.bytes), length: blob.data.length, freeWhenDone: false)) break } @@ -859,6 +895,40 @@ public final class Postbox { } } + private func messageIdsForAbsoluteIndexedIds(ids: [Int32]) -> [MessageId] { + if ids.count == 0 { + return [] + } + + var queryString = "SELECT completeId FROM peer_absolute_indexed_message_ids WHERE id IN (" + var first = true + for id in ids { + if first { + first = false + } else { + queryString += "," + } + queryString += "\(id)" + } + queryString += ")" + + var result: [MessageId] = [] + for row in self.database.prepare(queryString).run() { + let blob = row[0] as! Blob + let blobBytes = blob.data.bytes + + var peerIdValue: Int64 = 0 + memcpy(&peerIdValue, blobBytes, 8) + var messageIdNamespaceValue: Int32 = 0 + memcpy(&messageIdNamespaceValue, blobBytes + 8, 4) + var messageIdIdValue: Int32 = 0 + memcpy(&messageIdIdValue, blobBytes + 12, 4) + result.append(MessageId(peerId: PeerId(peerIdValue), namespace: messageIdNamespaceValue, id: messageIdIdValue)) + } + + return result + } + private func deleteMessagesWithIds(ids: [MessageId]) { for (peerId, messageIds) in Postbox.messageIdsGroupedByPeerId(ids) { let messageIdsByNamespace = Postbox.messageIdsGroupedByNamespace(messageIds) @@ -889,6 +959,21 @@ public final class Postbox { } queryString += ")" self.database.prepare(queryString).run(peerId.toInt64(), Int64(namespace)) + + if self.absoluteIndexedMessageNamespaces.contains(namespace) { + var queryString = "DELETE FROM peer_absolute_indexed_message_ids WHERE id IN (" + var first = true + for id in messageIds { + if first { + first = false + } else { + queryString += "," + } + queryString += "\(id.id)" + } + queryString += ")" + self.database.prepare(queryString).run() + } } for (namespace, messageIds) in messageIdsByNamespace { @@ -1263,7 +1348,6 @@ public final class Postbox { let sign = earlier ? "<" : ">" let order = earlier ? "DESC" : "ASC" - let statement = self.database.prepareCached("SELECT data, associatedMediaIds FROM peer_messages WHERE peerId = ? AND namespace = ? AND id \(sign) ? ORDER BY id \(order) LIMIT ?") let bound: Int64 if let id = id { bound = Int64(id) @@ -1273,15 +1357,25 @@ public final class Postbox { bound = Int64(Int32.min) } - for row in statement.run(Int64(peerId.toInt64()), Int64(namespace), bound, Int64(count)) { - let data = (row[0] as! Blob).data - let decoder = Decoder(buffer: ReadBuffer(memory: UnsafeMutablePointer(data.bytes), length: data.length, freeWhenDone: false)) - if let message = decoder.decodeRootObject() as? Message { - messages.append(message) + var statement: COpaquePointer = nil + sqlite3_prepare_v2(self.database.handle, "SELECT data, associatedMediaIds FROM peer_messages WHERE peerId=\(peerId.toInt64()) AND namespace=\(namespace) AND id \(sign) \(bound) ORDER BY id \(order) LIMIT \(count)", -1, &statement, nil) + + while true { + let result = sqlite3_step(statement) + if result == SQLITE_ROW { + let length = sqlite3_column_bytes(statement, 0) + let data = sqlite3_column_blob(statement, 0) + let decoder = Decoder(buffer: ReadBuffer(memory: UnsafeMutablePointer(data), length: Int(length), freeWhenDone: false)) + if let message = decoder.decodeRootObject() as? Message { + messages.append(message) + } else { + print("(PostBox: can't decode message)") + } } else { - print("(PostBox: can't decode message)") + break } } + sqlite3_finalize(statement) return self.renderedMessages(messages) } @@ -1289,23 +1383,32 @@ public final class Postbox { private func fetchPeerEntryIndicesRelative(earlier: Bool)(index: PeerViewEntryIndex?, count: Int) -> [PeerViewEntryIndex] { var entries: [PeerViewEntryIndex] = [] - let rows: Statement + var statement: COpaquePointer = nil if let index = index { let bound = Postbox.blobForPeerViewEntryIndex(index) let sign = earlier ? "<" : ">" let order = earlier ? "DESC" : "ASC" - let statement = self.database.prepareCached("SELECT entry FROM peer_entries WHERE entry \(sign) ? ORDER BY entry \(order) LIMIT ?") - rows = statement.run(bound, Int64(count)) + + sqlite3_prepare_v2(self.database.handle, "SELECT entry FROM peer_entries WHERE entry \(sign) ? ORDER BY entry \(order) LIMIT \(count)", -1, &statement, nil) + sqlite3_bind_blob(statement, 0, bound.data.bytes, Int32(bound.data.length), nil) + } else { let order = earlier ? "DESC" : "ASC" - let statement = self.database.prepareCached("SELECT entry FROM peer_entries ORDER BY entry \(order) LIMIT ?") - rows = statement.run(Int64(count)) + sqlite3_prepare_v2(self.database.handle, "SELECT entry FROM peer_entries ORDER BY entry \(order) LIMIT \(count)", -1, &statement, nil) } - for row in rows { - entries.append(Postbox.peerViewEntryIndexForBlob(row[0] as! Blob)) + while true { + let result = sqlite3_step(statement) + if result == SQLITE_ROW { + let length = sqlite3_column_bytes(statement, 0) + let data = sqlite3_column_blob(statement, 0) + entries.append(Postbox.peerViewEntryIndexForBuffer(ReadBuffer(memory: UnsafeMutablePointer(data), length: Int(length), freeWhenDone: false))) + } else { + break + } } + sqlite3_finalize(statement) return entries } @@ -1350,7 +1453,14 @@ public final class Postbox { entries.append(entry) } else { - print("(PostBox: missing message for peer entry)") + let entry: PeerViewEntry + if let peer = peer { + entry = PeerViewEntry(peer: peer, peerId: entryIndex.peerId, messageIndex: entryIndex.messageIndex) + } else { + entry = PeerViewEntry(peer: nil, peerId: entryIndex.peerId, messageIndex: entryIndex.messageIndex) + } + + entries.append(entry) } } @@ -1501,6 +1611,8 @@ public final class Postbox { self.queue.dispatch { let mutableView: MutableMessageView + let startTime = CFAbsoluteTimeGetCurrent() + let around = self.fetchMessagesAround(peerId, anchorId: id, count: count) if around.0.count == 0 { let tail = self.fetchMessagesTail(peerId, count: count + 1) @@ -1530,6 +1642,8 @@ public final class Postbox { mutableView = MutableMessageView(namespaces: self.messageNamespaces, count: count, earlier: around.1, messages: around.0, later: around.2) } + print("aroundMessageViewForPeerId fetch: \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms") + let record = (mutableView, Pipe()) let index: Bag<(MutableMessageView, Pipe)>.Index @@ -1573,7 +1687,6 @@ public final class Postbox { let startTime = CFAbsoluteTimeGetCurrent() let tail = self.fetchPeerEntriesRelative(true)(index: nil, count: count + 1) - self.fetchPeerEntriesRelative(true)(index: nil, count: count + 1) print("(Postbox fetchPeerEntriesRelative took \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms)")