This commit is contained in:
overtake 2017-06-16 12:18:45 +03:00
commit c09f88d732
7 changed files with 158 additions and 39 deletions

View File

@ -1267,10 +1267,11 @@
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CFLAGS = ( OTHER_CFLAGS = (
"-DSQLITE_TEMP_STORE=2",
"-DSQLITE_HAS_CODEC=1", "-DSQLITE_HAS_CODEC=1",
"-DSQLCIPHER_CRYPTO_CC=1", "-DSQLCIPHER_CRYPTO_CC=1",
"-DSQLITE_ENABLE_FTS3", "-DSQLITE_OMIT_DEPRECATED",
"-DSQLITE_ENABLE_FTS5",
"-DSQLITE_DEFAULT_MEMSTATUS=0",
); );
PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@ -1394,10 +1395,11 @@
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CFLAGS = ( OTHER_CFLAGS = (
"-DSQLITE_TEMP_STORE=2",
"-DSQLITE_HAS_CODEC=1", "-DSQLITE_HAS_CODEC=1",
"-DSQLCIPHER_CRYPTO_CC=1", "-DSQLCIPHER_CRYPTO_CC=1",
"-DSQLITE_ENABLE_FTS3", "-DSQLITE_OMIT_DEPRECATED",
"-DSQLITE_ENABLE_FTS5",
"-DSQLITE_DEFAULT_MEMSTATUS=0",
); );
PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@ -1642,10 +1644,11 @@
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CFLAGS = ( OTHER_CFLAGS = (
"-DSQLITE_TEMP_STORE=2",
"-DSQLITE_HAS_CODEC=1", "-DSQLITE_HAS_CODEC=1",
"-DSQLCIPHER_CRYPTO_CC=1", "-DSQLCIPHER_CRYPTO_CC=1",
"-DSQLITE_ENABLE_FTS3", "-DSQLITE_OMIT_DEPRECATED",
"-DSQLITE_ENABLE_FTS5",
"-DSQLITE_DEFAULT_MEMSTATUS=0",
); );
OTHER_SWIFT_FLAGS = "-DDEBUG"; OTHER_SWIFT_FLAGS = "-DDEBUG";
PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)";
@ -1675,10 +1678,11 @@
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CFLAGS = ( OTHER_CFLAGS = (
"-DSQLITE_TEMP_STORE=2",
"-DSQLITE_HAS_CODEC=1", "-DSQLITE_HAS_CODEC=1",
"-DSQLCIPHER_CRYPTO_CC=1", "-DSQLCIPHER_CRYPTO_CC=1",
"-DSQLITE_ENABLE_FTS3", "-DSQLITE_OMIT_DEPRECATED",
"-DSQLITE_ENABLE_FTS5",
"-DSQLITE_DEFAULT_MEMSTATUS=0",
); );
PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";

View File

@ -3,6 +3,7 @@ import Foundation
struct ChatListInclusionIndex { struct ChatListInclusionIndex {
let topMessageIndex: MessageIndex? let topMessageIndex: MessageIndex?
let inclusion: PeerChatListInclusion let inclusion: PeerChatListInclusion
var tags: [UInt16]?
func includedIndex(peerId: PeerId) -> ChatListIndex? { func includedIndex(peerId: PeerId) -> ChatListIndex? {
switch inclusion { switch inclusion {
@ -32,6 +33,17 @@ struct ChatListInclusionIndex {
} }
} }
private struct ChatListIndexFlags: OptionSet {
var rawValue: Int8
init(rawValue: Int8) {
self.rawValue = rawValue
}
static let hasIndex = ChatListIndexFlags(rawValue: 1 << 0)
static let hasTags = ChatListIndexFlags(rawValue: 1 << 1)
}
final class ChatListIndexTable: Table { final class ChatListIndexTable: Table {
static func tableSpec(_ id: Int32) -> ValueBoxTable { static func tableSpec(_ id: Int32) -> ValueBoxTable {
return ValueBoxTable(id: id, keyType: .int64) return ValueBoxTable(id: id, keyType: .int64)
@ -66,7 +78,7 @@ final class ChatListIndexTable: Table {
if self.updatedPreviousCachedIndices[peerId] == nil { if self.updatedPreviousCachedIndices[peerId] == nil {
self.updatedPreviousCachedIndices[peerId] = current self.updatedPreviousCachedIndices[peerId] = current
} }
let updated = ChatListInclusionIndex(topMessageIndex: index, inclusion: current.inclusion) let updated = ChatListInclusionIndex(topMessageIndex: index, inclusion: current.inclusion, tags: current.tags)
self.cachedIndices[peerId] = updated self.cachedIndices[peerId] = updated
return updated return updated
} }
@ -76,7 +88,7 @@ final class ChatListIndexTable: Table {
if self.updatedPreviousCachedIndices[peerId] == nil { if self.updatedPreviousCachedIndices[peerId] == nil {
self.updatedPreviousCachedIndices[peerId] = current self.updatedPreviousCachedIndices[peerId] = current
} }
let updated = ChatListInclusionIndex(topMessageIndex: current.topMessageIndex, inclusion: inclusion) let updated = ChatListInclusionIndex(topMessageIndex: current.topMessageIndex, inclusion: inclusion, tags: current.tags)
self.cachedIndices[peerId] = updated self.cachedIndices[peerId] = updated
return updated return updated
} }
@ -88,9 +100,11 @@ final class ChatListIndexTable: Table {
if let value = self.valueBox.get(self.table, key: self.key(peerId)) { if let value = self.valueBox.get(self.table, key: self.key(peerId)) {
let topMessageIndex: MessageIndex? let topMessageIndex: MessageIndex?
var hasIndex: Int8 = 0 var flagsValue: Int8 = 0
value.read(&hasIndex, offset: 0, length: 1) value.read(&flagsValue, offset: 0, length: 1)
if hasIndex != 0 { let flags = ChatListIndexFlags(rawValue: flagsValue)
if flags.contains(.hasIndex) {
var idNamespace: Int32 = 0 var idNamespace: Int32 = 0
var idId: Int32 = 0 var idId: Int32 = 0
var idTimestamp: Int32 = 0 var idTimestamp: Int32 = 0
@ -131,11 +145,24 @@ final class ChatListIndexTable: Table {
preconditionFailure() preconditionFailure()
} }
let inclusionIndex = ChatListInclusionIndex(topMessageIndex: topMessageIndex, inclusion: inclusion) var tags: [UInt16]?
if flags.contains(.hasTags) {
var count: UInt16 = 0
value.read(&count, offset: 0, length: 2)
var resultTags: [UInt16] = []
for _ in 0 ..< Int(count) {
var tag: UInt16 = 0
value.read(&tag, offset: 0, length: 2)
resultTags.append(tag)
}
tags = resultTags
}
let inclusionIndex = ChatListInclusionIndex(topMessageIndex: topMessageIndex, inclusion: inclusion, tags: tags)
self.cachedIndices[peerId] = inclusionIndex self.cachedIndices[peerId] = inclusionIndex
return inclusionIndex return inclusionIndex
} else { } else {
return ChatListInclusionIndex(topMessageIndex: nil, inclusion: .notSpecified) return ChatListInclusionIndex(topMessageIndex: nil, inclusion: .notSpecified, tags: nil)
} }
} }
} }
@ -162,18 +189,26 @@ final class ChatListIndexTable: Table {
let writeBuffer = WriteBuffer() let writeBuffer = WriteBuffer()
var flags: ChatListIndexFlags = []
if index.topMessageIndex != nil {
flags.insert(.hasIndex)
}
if index.tags != nil {
flags.insert(.hasTags)
}
var flagsValue = flags.rawValue
writeBuffer.write(&flagsValue, offset: 0, length: 1)
if let topMessageIndex = index.topMessageIndex { if let topMessageIndex = index.topMessageIndex {
var hasIndex: Int8 = 1
writeBuffer.write(&hasIndex, offset: 0, length: 1)
var idNamespace: Int32 = topMessageIndex.id.namespace var idNamespace: Int32 = topMessageIndex.id.namespace
var idId: Int32 = topMessageIndex.id.id var idId: Int32 = topMessageIndex.id.id
var idTimestamp: Int32 = topMessageIndex.timestamp var idTimestamp: Int32 = topMessageIndex.timestamp
writeBuffer.write(&idNamespace, offset: 0, length: 4) writeBuffer.write(&idNamespace, offset: 0, length: 4)
writeBuffer.write(&idId, offset: 0, length: 4) writeBuffer.write(&idId, offset: 0, length: 4)
writeBuffer.write(&idTimestamp, offset: 0, length: 4) writeBuffer.write(&idTimestamp, offset: 0, length: 4)
} else {
var hasIndex: Int8 = 0
writeBuffer.write(&hasIndex, offset: 0, length: 1)
} }
switch index.inclusion { switch index.inclusion {
@ -205,6 +240,16 @@ final class ChatListIndexTable: Table {
} }
} }
if let tags = index.tags {
var count = UInt16(tags.count)
writeBuffer.write(&count, offset: 0, length: 2)
for tag in tags {
var tagValue: UInt16 = tag
writeBuffer.write(&tagValue, offset: 0, length: 2)
}
}
withExtendedLifetime(writeBuffer, { withExtendedLifetime(writeBuffer, {
self.valueBox.set(self.table, key: self.key(peerId), value: writeBuffer.readBufferNoCopy()) self.valueBox.set(self.table, key: self.key(peerId), value: writeBuffer.readBufferNoCopy())
}) })

View File

@ -106,7 +106,13 @@ public final class Database {
/// ///
/// - parameter SQL: A batch of zero or more semicolon-separated SQL statements. /// - parameter SQL: A batch of zero or more semicolon-separated SQL statements.
public func execute(_ SQL: String) -> Bool { public func execute(_ SQL: String) -> Bool {
return sqlite3_exec(self.handle, SQL, nil, nil, nil) == SQLITE_OK let res = sqlite3_exec(self.handle, SQL, nil, nil, nil)
if res == SQLITE_OK {
return true
} else {
print("SQL error \(res) on SQL")
return false
}
} }
} }

View File

@ -2,7 +2,7 @@ import Foundation
public enum PeerIndexNameRepresentation: Equatable { public enum PeerIndexNameRepresentation: Equatable {
case title(title: String, addressName: String?) case title(title: String, addressName: String?)
case personName(first: String, last: String, addressName: String?) case personName(first: String, last: String, addressName: String?, phoneNumber: String?)
public static func ==(lhs: PeerIndexNameRepresentation, rhs: PeerIndexNameRepresentation) -> Bool { public static func ==(lhs: PeerIndexNameRepresentation, rhs: PeerIndexNameRepresentation) -> Bool {
switch lhs { switch lhs {
@ -12,14 +12,41 @@ public enum PeerIndexNameRepresentation: Equatable {
} else { } else {
return false return false
} }
case let .personName(lhsFirst, lhsLast, lhsAddressName): case let .personName(lhsFirst, lhsLast, lhsAddressName, lhsPhoneNumber):
if case let .personName(rhsFirst, rhsLast, rhsAddressName) = rhs, lhsFirst == rhsFirst, lhsLast == rhsLast, lhsAddressName == rhsAddressName { if case let .personName(rhsFirst, rhsLast, rhsAddressName, rhsPhoneNumber) = rhs, lhsFirst == rhsFirst, lhsLast == rhsLast, lhsAddressName == rhsAddressName, lhsPhoneNumber == rhsPhoneNumber {
return true return true
} else { } else {
return false return false
} }
} }
} }
public var isEmpty: Bool {
switch self {
case let .title(title, addressName):
if !title.isEmpty {
return false
}
if let addressName = addressName, !addressName.isEmpty {
return false
}
return true
case let .personName(first, last, addressName, phoneNumber):
if !first.isEmpty {
return false
}
if !last.isEmpty {
return false
}
if let addressName = addressName, !addressName.isEmpty {
return false
}
if let phoneNumber = phoneNumber, !phoneNumber.isEmpty {
return false
}
return true
}
}
} }
public enum PeerNameIndex { public enum PeerNameIndex {
@ -32,7 +59,7 @@ extension PeerIndexNameRepresentation {
switch self { switch self {
case let .title(title, _): case let .title(title, _):
return title return title
case let .personName(first, last, _): case let .personName(first, last, _, _):
switch index { switch index {
case .firstNameFirst: case .firstNameFirst:
return first + last return first + last
@ -68,12 +95,15 @@ extension PeerIndexNameRepresentation {
tokens.append(contentsOf: stringIndexTokens(addressName, transliteration: .none)) tokens.append(contentsOf: stringIndexTokens(addressName, transliteration: .none))
} }
return tokens return tokens
case let .personName(first, last, addressName): case let .personName(first, last, addressName, phoneNumber):
var tokens: [ValueBoxKey] = stringIndexTokens(first, transliteration: .combined) var tokens: [ValueBoxKey] = stringIndexTokens(first, transliteration: .combined)
tokens.append(contentsOf: stringIndexTokens(last, transliteration: .combined)) tokens.append(contentsOf: stringIndexTokens(last, transliteration: .combined))
if let addressName = addressName { if let addressName = addressName {
tokens.append(contentsOf: stringIndexTokens(addressName, transliteration: .none)) tokens.append(contentsOf: stringIndexTokens(addressName, transliteration: .none))
} }
if let phoneNumber = phoneNumber {
tokens.append(contentsOf: stringIndexTokens(phoneNumber, transliteration: .none))
}
return tokens return tokens
} }
} }

View File

@ -213,7 +213,15 @@ final class PeerNameIndexTable: Table {
updatedTokens = updatedName.indexTokens updatedTokens = updatedName.indexTokens
} else { } else {
if let peer = self.peerTable.get(peerId) { if let peer = self.peerTable.get(peerId) {
updatedTokens = peer.indexName.indexTokens if let associatedPeerId = peer.associatedPeerId {
if let associatedPeer = self.peerTable.get(associatedPeerId) {
updatedTokens = associatedPeer.indexName.indexTokens
} else {
updatedTokens = []
}
} else {
updatedTokens = peer.indexName.indexTokens
}
} else { } else {
//assertionFailure() //assertionFailure()
updatedTokens = [] updatedTokens = []

View File

@ -1356,8 +1356,23 @@ public final class Postbox {
if let updatedPeer = update(currentPeer, peer) { if let updatedPeer = update(currentPeer, peer) {
self.peerTable.set(updatedPeer) self.peerTable.set(updatedPeer)
self.currentUpdatedPeers[updatedPeer.id] = updatedPeer self.currentUpdatedPeers[updatedPeer.id] = updatedPeer
if currentPeer?.indexName != updatedPeer.indexName { var previousIndexNameWasEmpty = true
self.peerNameIndexTable.markPeerNameUpdated(peerId: peer.id, name: updatedPeer.indexName)
if let currentPeer = currentPeer {
if !currentPeer.indexName.isEmpty {
previousIndexNameWasEmpty = false
}
}
let indexNameIsEmpty = updatedPeer.indexName.isEmpty
if !previousIndexNameWasEmpty || !indexNameIsEmpty {
if currentPeer?.indexName != updatedPeer.indexName {
self.peerNameIndexTable.markPeerNameUpdated(peerId: peer.id, name: updatedPeer.indexName)
for reverseAssociatedPeerId in self.reverseAssociatedPeerTable.get(peerId: peer.id) {
self.peerNameIndexTable.markPeerNameUpdated(peerId: reverseAssociatedPeerId, name: updatedPeer.indexName)
}
}
} }
} }
} }
@ -1800,30 +1815,41 @@ public final class Postbox {
} |> switchToLatest } |> switchToLatest
} }
public func searchPeers(query: String) -> Signal<[Peer], NoError> { public func searchPeers(query: String) -> Signal<[RenderedPeer], NoError> {
return self.modify { modifier -> Signal<[Peer], NoError> in return self.modify { modifier -> Signal<[RenderedPeer], NoError> in
var peerIds = Set<PeerId>() var peerIds = Set<PeerId>()
var chatPeers: [Peer] = [] var chatPeers: [RenderedPeer] = []
let (chatPeerIds, contactPeerIds) = self.peerNameIndexTable.matchingPeerIds(tokens: (regular: stringIndexTokens(query, transliteration: .none), transliterated: stringIndexTokens(query, transliteration: .transliterated)), categories: [.chats, .contacts], chatListIndexTable: self.chatListIndexTable, contactTable: self.contactsTable, reverseAssociatedPeerTable: self.reverseAssociatedPeerTable) let (chatPeerIds, contactPeerIds) = self.peerNameIndexTable.matchingPeerIds(tokens: (regular: stringIndexTokens(query, transliteration: .none), transliterated: stringIndexTokens(query, transliteration: .transliterated)), categories: [.chats, .contacts], chatListIndexTable: self.chatListIndexTable, contactTable: self.contactsTable, reverseAssociatedPeerTable: self.reverseAssociatedPeerTable)
for peerId in chatPeerIds { for peerId in chatPeerIds {
if let peer = self.peerTable.get(peerId) { if let peer = self.peerTable.get(peerId) {
chatPeers.append(peer) var peers = SimpleDictionary<PeerId, Peer>()
peers[peer.id] = peer
if let associatedPeerId = peer.associatedPeerId {
if let associatedPeer = self.peerTable.get(associatedPeerId) {
peers[associatedPeer.id] = associatedPeer
}
}
chatPeers.append(RenderedPeer(peerId: peer.id, peers: peers))
peerIds.insert(peerId) peerIds.insert(peerId)
} }
} }
var contactPeers: [Peer] = [] var contactPeers: [RenderedPeer] = []
for peerId in contactPeerIds { for peerId in contactPeerIds {
if !peerIds.contains(peerId) { if !peerIds.contains(peerId) {
if let peer = self.peerTable.get(peerId) { if let peer = self.peerTable.get(peerId) {
contactPeers.append(peer) var peers = SimpleDictionary<PeerId, Peer>()
peers[peer.id] = peer
contactPeers.append(RenderedPeer(peerId: peer.id, peers: peers))
} }
} }
} }
contactPeers.sort(by: { $0.indexName.indexName(.lastNameFirst) < $1.indexName.indexName(.lastNameFirst) }) contactPeers.sort(by: { lhs, rhs in
lhs.peers[lhs.peerId]!.indexName.indexName(.lastNameFirst) < rhs.peers[rhs.peerId]!.indexName.indexName(.lastNameFirst)
})
return .single(chatPeers + contactPeers) return .single(chatPeers + contactPeers)
} |> switchToLatest } |> switchToLatest
} }

View File

@ -149,7 +149,7 @@ final class SqliteValueBox: ValueBox {
//database = Database(path)! //database = Database(path)!
} }
sqlite3_busy_timeout(database.handle, 10000000) sqlite3_busy_timeout(database.handle, 1000 * 10000)
var resultCode: Bool var resultCode: Bool
@ -158,9 +158,9 @@ final class SqliteValueBox: ValueBox {
assert(resultCode) assert(resultCode)
resultCode = database.execute("PRAGMA synchronous=NORMAL") resultCode = database.execute("PRAGMA synchronous=NORMAL")
assert(resultCode) assert(resultCode)
//database.execute("PRAGMA temp_store=MEMORY") resultCode = database.execute("PRAGMA temp_store=MEMORY")
resultCode = database.execute("PRAGMA wal_autocheckpoint=500")
assert(resultCode) assert(resultCode)
//resultCode = database.execute("PRAGMA wal_autocheckpoint=500")
//database.execute("PRAGMA journal_size_limit=1536") //database.execute("PRAGMA journal_size_limit=1536")
/*var statement: OpaquePointer? = nil /*var statement: OpaquePointer? = nil