Fix one of the causes of watchdog crashes in WidgetDataEncoder by fetching just the count of starred articles — instead of fetching all the starred articles and counting them, which can take a long time.

This commit is contained in:
Brent Simmons 2022-05-12 21:56:49 -07:00
parent fdadb80863
commit a0e8ca00ee
5 changed files with 81 additions and 16 deletions

View File

@ -718,6 +718,10 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
database.fetchStarredAndUnreadCount(for: flattenedWebFeeds().webFeedIDs(), completion: completion)
}
public func fetchCountForStarredArticles() throws -> Int {
return try database.fetchStarredArticlesCount(flattenedWebFeeds().webFeedIDs())
}
public func fetchUnreadArticleIDs(_ completion: @escaping ArticleIDsCompletionBlock) {
database.fetchUnreadArticleIDsAsync(completion: completion)
}

View File

@ -393,6 +393,17 @@ public final class AccountManager: UnreadCountProvider {
}
}
}
// MARK: - Fetching Article Counts
public func fetchCountForStarredArticles() throws -> Int {
precondition(Thread.isMainThread)
var count = 0
for account in activeAccounts {
count += try account.fetchCountForStarredArticles()
}
return count
}
// MARK: - Caches

View File

@ -114,6 +114,10 @@ public final class ArticlesDatabase {
return try articlesTable.fetchStarredArticles(webFeedIDs, limit)
}
public func fetchStarredArticlesCount(_ webFeedIDs: Set<String>) throws -> Int {
return try articlesTable.fetchStarredArticlesCount(webFeedIDs)
}
public func fetchArticlesMatching(_ searchString: String, _ webFeedIDs: Set<String>) throws -> Set<Article> {
return try articlesTable.fetchArticlesMatching(searchString, webFeedIDs)
}

View File

@ -32,7 +32,8 @@ final class ArticlesTable: DatabaseTable {
let articleCutoffDate = Date().bySubtracting(days: 90)
private typealias ArticlesFetchMethod = (FMDatabase) -> Set<Article>
private typealias ArticlesCountFetchMethod = (FMDatabase) -> Int
init(name: String, accountID: String, queue: DatabaseQueue, retentionStyle: ArticlesDatabase.RetentionStyle) {
self.name = name
@ -103,6 +104,10 @@ final class ArticlesTable: DatabaseTable {
fetchArticlesAsync({ self.fetchStarredArticles(webFeedIDs, limit, $0) }, completion)
}
func fetchStarredArticlesCount(_ webFeedIDs: Set<String>) throws -> Int {
return try fetchArticlesCount{ self.fetchStarredArticlesCount(webFeedIDs, $0) }
}
// MARK: - Fetching Search Articles
func fetchArticlesMatching(_ searchString: String) throws -> Set<Article> {
@ -671,6 +676,23 @@ private extension ArticlesTable {
return articles
}
private func fetchArticlesCount(_ fetchMethod: @escaping ArticlesCountFetchMethod) throws -> Int {
var articlesCount = 0
var error: DatabaseError? = nil
queue.runInDatabaseSync { databaseResult in
switch databaseResult {
case .success(let database):
articlesCount = fetchMethod(database)
case .failure(let databaseError):
error = databaseError
}
}
if let error = error {
throw(error)
}
return articlesCount
}
private func fetchArticlesAsync(_ fetchMethod: @escaping ArticlesFetchMethod, _ completion: @escaping ArticleSetResultBlock) {
queue.runInDatabase { databaseResult in
@ -745,6 +767,19 @@ private extension ArticlesTable {
return articlesWithSQL(sql, parameters, database)
}
func fetchArticleCountsWithWhereClause(_ database: FMDatabase, whereClause: String, parameters: [AnyObject]) -> Int {
let sql = "select count(*) from articles natural join statuses where \(whereClause);"
guard let resultSet = database.executeQuery(sql, withArgumentsIn: parameters) else {
return 0
}
var articlesCount = 0
if resultSet.next() {
articlesCount = resultSet.long(forColumnIndex: 0)
}
resultSet.close()
return articlesCount
}
func fetchArticlesMatching(_ searchString: String, _ database: FMDatabase) -> Set<Article> {
let sql = "select rowid from search where search match ?;"
let sqlSearchString = sqliteSearchString(with: searchString)
@ -840,20 +875,31 @@ private extension ArticlesTable {
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters)
}
func fetchStarredArticles(_ webFeedIDs: Set<String>, _ limit: Int?, _ database: FMDatabase) -> Set<Article> {
// select * from articles natural join statuses where feedID in ('http://ranchero.com/xml/rss.xml') and starred=1;
if webFeedIDs.isEmpty {
return Set<Article>()
}
let parameters = webFeedIDs.map { $0 as AnyObject }
let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(webFeedIDs.count))!
var whereClause = "feedID in \(placeholders) and starred=1"
if let limit = limit {
whereClause.append(" order by coalesce(datePublished, dateModified, dateArrived) desc limit \(limit)")
}
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters)
}
func fetchStarredArticles(_ webFeedIDs: Set<String>, _ limit: Int?, _ database: FMDatabase) -> Set<Article> {
// select * from articles natural join statuses where feedID in ('http://ranchero.com/xml/rss.xml') and starred=1;
if webFeedIDs.isEmpty {
return Set<Article>()
}
let parameters = webFeedIDs.map { $0 as AnyObject }
let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(webFeedIDs.count))!
var whereClause = "feedID in \(placeholders) and starred=1"
if let limit = limit {
whereClause.append(" order by coalesce(datePublished, dateModified, dateArrived) desc limit \(limit)")
}
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters)
}
func fetchStarredArticlesCount(_ webFeedIDs: Set<String>, _ database: FMDatabase) -> Int {
// select count from articles natural join statuses where feedID in ('http://ranchero.com/xml/rss.xml') and starred=1;
if webFeedIDs.isEmpty {
return 0
}
let parameters = webFeedIDs.map { $0 as AnyObject }
let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(webFeedIDs.count))!
let whereClause = "feedID in \(placeholders) and starred=1"
return fetchArticleCountsWithWhereClause(database, whereClause: whereClause, parameters: parameters)
}
func fetchArticlesMatching(_ searchString: String, _ webFeedIDs: Set<String>, _ database: FMDatabase) -> Set<Article> {
let articles = fetchArticlesMatching(searchString, database)
// TODO: include the feedIDs in the SQL rather than filtering here.

View File

@ -73,7 +73,7 @@ public final class WidgetDataEncoder {
let latestData = WidgetData(currentUnreadCount: SmartFeedsController.shared.unreadFeed.unreadCount,
currentTodayCount: SmartFeedsController.shared.todayFeed.unreadCount,
currentStarredCount: try! SmartFeedsController.shared.starredFeed.fetchArticles().count,
currentStarredCount: try AccountManager.shared.fetchCountForStarredArticles(),
unreadArticles: unread,
starredArticles: starred,
todayArticles:today,