From 5872893293f0daf95359eeb5acde9bd70142dbe7 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Mon, 9 Dec 2019 14:06:03 -0700 Subject: [PATCH] Prevent calls to database while it is suspended. Issue #1424 --- .../ArticlesDatabase/ArticlesTable.swift | 47 +++++++++++++++++-- .../ArticlesDatabase/StatusesTable.swift | 3 ++ Frameworks/SyncDatabase/SyncStatusTable.swift | 26 ++++++++++ 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/Frameworks/ArticlesDatabase/ArticlesTable.swift b/Frameworks/ArticlesDatabase/ArticlesTable.swift index 6859185a3..8ef73e859 100644 --- a/Frameworks/ArticlesDatabase/ArticlesTable.swift +++ b/Frameworks/ArticlesDatabase/ArticlesTable.swift @@ -163,6 +163,9 @@ final class ArticlesTable: DatabaseTable { func fetchArticlesMatching(_ searchString: String) -> Set
{ var articles: Set
= Set
() + guard !queue.isSuspended else { + return articles + } queue.runInDatabaseSync { (database) in articles = self.fetchArticlesMatching(searchString, database) } @@ -250,6 +253,11 @@ final class ArticlesTable: DatabaseTable { articleIDs.formUnion(parsedItems.articleIDs()) } + guard !self.queue.isSuspended else { + self.callUpdateArticlesCompletionBlock(nil, nil, completion) + return + } + self.queue.runInTransaction { (database) in let statusesDictionary = self.statusesTable.ensureStatusesForArticleIDs(articleIDs, read, database) //1 assert(statusesDictionary.count == articleIDs.count) @@ -286,6 +294,13 @@ final class ArticlesTable: DatabaseTable { } func ensureStatuses(_ articleIDs: Set, _ defaultRead: Bool, _ statusKey: ArticleStatus.Key, _ flag: Bool, completionHandler: VoidCompletionBlock? = nil) { + guard !queue.isSuspended else { + if let handler = completionHandler { + callVoidCompletionBlock(handler) + } + return + } + queue.runInTransaction { (database) in let statusesDictionary = self.statusesTable.ensureStatusesForArticleIDs(articleIDs, defaultRead, database) let statuses = Set(statusesDictionary.values) @@ -305,7 +320,11 @@ final class ArticlesTable: DatabaseTable { } var unreadCountDictionary = UnreadCountDictionary() - + guard !queue.isSuspended else { + completion(unreadCountDictionary) + return + } + queue.runInDatabase { (database) in for webFeedID in webFeedIDs { unreadCountDictionary[webFeedID] = self.fetchUnreadCount(webFeedID, database) @@ -347,6 +366,11 @@ final class ArticlesTable: DatabaseTable { let cutoffDate = articleCutoffDate + guard !queue.isSuspended else { + completion(UnreadCountDictionary()) + return + } + queue.runInDatabase { (database) in let sql = "select distinct feedID, count(*) from articles natural join statuses where read=0 and userDeleted=0 and (starred=1 or (datePublished > ? or (datePublished is null and dateArrived > ?))) group by feedID;" @@ -372,7 +396,7 @@ final class ArticlesTable: DatabaseTable { } func fetchStarredAndUnreadCount(_ webFeedIDs: Set, _ callback: @escaping (Int) -> Void) { - if webFeedIDs.isEmpty { + if webFeedIDs.isEmpty || queue.isSuspended { callback(0) return } @@ -410,9 +434,15 @@ final class ArticlesTable: DatabaseTable { func mark(_ articles: Set
, _ statusKey: ArticleStatus.Key, _ flag: Bool) -> Set? { var statuses: Set? + + guard !self.queue.isSuspended else { + return statuses + } + self.queue.runInTransactionSync { (database) in statuses = self.statusesTable.mark(articles.statuses(), statusKey, flag, database) } + return statuses } @@ -453,7 +483,7 @@ final class ArticlesTable: DatabaseTable { /// This deletes from the articles and articleStatuses tables, /// and, via a trigger, it also deletes from the search index. func deleteArticlesNotInSubscribedToFeedIDs(_ webFeedIDs: Set) { - if webFeedIDs.isEmpty { + if webFeedIDs.isEmpty || queue.isSuspended { return } queue.runInDatabase { (database) in @@ -481,6 +511,9 @@ private extension ArticlesTable { private func fetchArticles(_ fetchMethod: @escaping ArticlesFetchMethod) -> Set
{ var articles = Set
() + guard !queue.isSuspended else { + return articles + } queue.runInDatabaseSync { (database) in articles = fetchMethod(database) } @@ -488,6 +521,10 @@ private extension ArticlesTable { } private func fetchArticlesAsync(_ fetchMethod: @escaping ArticlesFetchMethod, _ callback: @escaping ArticleSetBlock) { + guard !queue.isSuspended else { + callback(Set
()) + return + } queue.runInDatabase { (database) in let articles = fetchMethod(database) DispatchQueue.main.async { @@ -645,6 +682,10 @@ private extension ArticlesTable { } func fetchArticleIDsAsync(_ statusKey: ArticleStatus.Key, _ value: Bool, _ webFeedIDs: Set, _ callback: @escaping (Set) -> Void) { + guard !queue.isSuspended else { + callback(Set()) + return + } queue.runInDatabase { database in let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(webFeedIDs.count))! var sql = "select articleID from articles natural join statuses where feedID in \(placeholders) and \(statusKey.rawValue)=" diff --git a/Frameworks/ArticlesDatabase/StatusesTable.swift b/Frameworks/ArticlesDatabase/StatusesTable.swift index 745bd9efb..ff145540c 100644 --- a/Frameworks/ArticlesDatabase/StatusesTable.swift +++ b/Frameworks/ArticlesDatabase/StatusesTable.swift @@ -88,6 +88,9 @@ final class StatusesTable: DatabaseTable { func fetchArticleIDs(_ sql: String) -> Set { var articleIDs = Set() + guard !queue.isSuspended else { + return articleIDs + } queue.runInDatabaseSync { (database) in guard let resultSet = database.executeQuery(sql, withArgumentsIn: nil) else { return diff --git a/Frameworks/SyncDatabase/SyncStatusTable.swift b/Frameworks/SyncDatabase/SyncStatusTable.swift index 55361205f..681b2f780 100644 --- a/Frameworks/SyncDatabase/SyncStatusTable.swift +++ b/Frameworks/SyncDatabase/SyncStatusTable.swift @@ -23,6 +23,10 @@ struct SyncStatusTable: DatabaseTable { func selectForProcessing() -> [SyncStatus] { var statuses: Set? = nil + guard !queue.isSuspended else { + return [SyncStatus]() + } + queue.runInDatabaseSync { database in let updateSQL = "update syncStatus set selected = true" database.executeUpdate(updateSQL, withArgumentsIn: nil) @@ -39,6 +43,10 @@ struct SyncStatusTable: DatabaseTable { func selectPendingCount() -> Int { var count: Int = 0 + guard !queue.isSuspended else { + return count + } + queue.runInDatabaseSync { database in let sql = "select count(*) from syncStatus" if let resultSet = database.executeQuery(sql, withArgumentsIn: nil) { @@ -50,6 +58,12 @@ struct SyncStatusTable: DatabaseTable { } func resetSelectedForProcessing(_ articleIDs: [String], completionHandler: VoidCompletionBlock? = nil) { + guard !queue.isSuspended else { + if let handler = completionHandler { + callVoidCompletionBlock(handler) + } + return + } queue.runInTransaction { database in let parameters = articleIDs.map { $0 as AnyObject } let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(articleIDs.count))! @@ -62,6 +76,12 @@ struct SyncStatusTable: DatabaseTable { } func deleteSelectedForProcessing(_ articleIDs: [String], completionHandler: VoidCompletionBlock? = nil) { + guard !queue.isSuspended else { + if let handler = completionHandler { + callVoidCompletionBlock(handler) + } + return + } queue.runInTransaction { database in let parameters = articleIDs.map { $0 as AnyObject } let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(articleIDs.count))! @@ -74,6 +94,12 @@ struct SyncStatusTable: DatabaseTable { } func insertStatuses(_ statuses: [SyncStatus], completionHandler: VoidCompletionBlock? = nil) { + guard !queue.isSuspended else { + if let handler = completionHandler { + callVoidCompletionBlock(handler) + } + return + } queue.runInTransaction { database in let statusArray = statuses.map { $0.databaseDictionary() } self.insertRows(statusArray, insertType: .orReplace, in: database)