improve global search performance

pull/541/head
Ryan Zhao 3 years ago
parent e8e120666b
commit a86310b0f5

@ -13,6 +13,7 @@ class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSo
}
}
var recentSearchResults: [String] = Array(Storage.shared.getRecentSearchResults().reversed())
var defaultSearchResults: HomeScreenSearchResultSet = HomeScreenSearchResultSet.noteToSelfOnly
var searchResultSet: HomeScreenSearchResultSet = HomeScreenSearchResultSet.empty
private var lastSearchText: String?
var searcher: FullTextSearcher {
@ -106,30 +107,10 @@ class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSo
var refreshTimer: Timer?
private func refreshSearchResults() {
guard !searchResultSet.isEmpty else {
// To avoid incorrectly showing the "no results" state,
// always search immediately if the current result set is empty.
refreshTimer?.invalidate()
refreshTimer = nil
updateSearchResults(searchText: searchText)
return
}
if refreshTimer != nil {
// Don't start a new refresh timer if there's already one active.
return
}
refreshTimer?.invalidate()
refreshTimer = WeakTimer.scheduledTimer(timeInterval: 0.1, target: self, userInfo: nil, repeats: false) { [weak self] _ in
guard let self = self else {
return
}
guard let self = self else { return }
self.updateSearchResults(searchText: self.searchText)
self.refreshTimer = nil
}
}
@ -137,7 +118,7 @@ class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSo
let searchText = rawSearchText.stripped
guard searchText.count > 0 else {
searchResultSet = HomeScreenSearchResultSet.noteToSelfOnly
searchResultSet = defaultSearchResults
lastSearchText = nil
reloadTableData()
return
@ -159,6 +140,7 @@ class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSo
self.searchResultSet = results
self.isLoading = false
self.reloadTableData()
self.refreshTimer = nil
})
}

@ -67,6 +67,7 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage)
[self loadDatabase];
_dbReadPool = [[YapDatabaseConnectionPool alloc] initWithDatabase:self.database];
_dbReadPool.connectionLimit = 10; // Increase max read connection limit. Default is 3.
_dbReadWriteConnection = [self newDatabaseConnection];
_uiDatabaseConnection = [self newDatabaseConnection];

@ -30,6 +30,8 @@ public class FullTextSearchFinder: NSObject {
private static var tsAccountManager: TSAccountManager {
return TSAccountManager.sharedInstance()
}
public var newQueryTimestamp: UInt64 = 0
// MARK: - Querying
@ -89,6 +91,13 @@ public class FullTextSearchFinder: NSObject {
guard let ext: YapDatabaseFullTextSearchTransaction = ext(transaction: transaction) else {
return
}
// HACK: Full text search is too expensive even though we drop the max search results
// to a reasonable number. And the async read can sometimes block a thread and make
// other read threads wait for it to finish. The timestamp is a workaround to ensure
// only one thread can be running the full text search at one time.
let currentQueryTimestamp = NSDate.millisecondTimestamp()
newQueryTimestamp = currentQueryTimestamp
let query = FullTextSearchFinder.query(searchText: searchText)
@ -99,7 +108,7 @@ public class FullTextSearchFinder: NSObject {
snippetOptions.endMatchText = ""
snippetOptions.numberOfTokens = 5
ext.enumerateKeysAndObjects(matching: query, with: snippetOptions) { (snippet: String, _: String, _: String, object: Any, stop: UnsafeMutablePointer<ObjCBool>) in
guard searchResultCount < maxSearchResults else {
guard searchResultCount < maxSearchResults && currentQueryTimestamp >= self.newQueryTimestamp else {
stop.pointee = true
return
}

@ -82,7 +82,6 @@ public final class ProfilePictureView : UIView {
update()
} else { // A one-to-one chat
let thread = thread as! TSContactThread
hasTappableProfilePicture = OWSProfileManager.shared().profileAvatar(forRecipientId: thread.contactSessionID()) != nil
update(for: thread.contactSessionID())
}
}
@ -92,8 +91,10 @@ public final class ProfilePictureView : UIView {
func getProfilePicture(of size: CGFloat, for publicKey: String) -> UIImage? {
guard !publicKey.isEmpty else { return nil }
if let profilePicture = OWSProfileManager.shared().profileAvatar(forRecipientId: publicKey) {
hasTappableProfilePicture = true
return profilePicture
} else {
hasTappableProfilePicture = false
// TODO: Pass in context?
let displayName = Storage.shared.getContact(with: publicKey)?.name ?? publicKey
return Identicon.generatePlaceholderIcon(seed: publicKey, text: displayName, size: size)

Loading…
Cancel
Save