Optimize media deletion

This commit is contained in:
Ali 2019-11-12 17:42:23 +04:00
parent c08b3c6f81
commit c257d42967
7 changed files with 79 additions and 36 deletions

View File

@ -929,6 +929,32 @@ public final class MediaBox {
unlink(paths.partial + ".meta")
self.fileContexts.removeValue(forKey: id)
}
let uniqueIds = Set(ids.map { $0.id.uniqueId })
var pathsToDelete: [String] = []
for cacheType in ["cache", "short-cache"] {
if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: "\(self.basePath)/\(cacheType)"), includingPropertiesForKeys: [], options: [.skipsSubdirectoryDescendants], errorHandler: nil) {
while let item = enumerator.nextObject() {
guard let url = item as? NSURL, let path = url.path, let fileName = url.lastPathComponent else {
continue
}
if let range = fileName.range(of: ":") {
let resourceId = String(fileName[fileName.startIndex ..< range.lowerBound])
if uniqueIds.contains(resourceId) {
pathsToDelete.append(path)
}
}
}
}
}
for path in pathsToDelete {
unlink(path)
}
subscriber.putCompletion()
}
return EmptyDisposable

View File

@ -2278,18 +2278,26 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
}
}
case let .DeleteMessagesWithGlobalIds(ids):
var resourceIds: [WrappedMediaResourceId] = []
transaction.deleteMessagesWithGlobalIds(ids, forEachMedia: { media in
processRemovedMedia(mediaBox, media)
addMessageMediaResourceIdsToRemove(media: media, resourceIds: &resourceIds)
})
if !resourceIds.isEmpty {
let _ = mediaBox.removeCachedResources(Set(resourceIds)).start()
}
case let .DeleteMessages(ids):
deleteMessages(transaction: transaction, mediaBox: mediaBox, ids: ids)
case let .UpdateMinAvailableMessage(id):
if let message = transaction.getMessage(id) {
updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: id.peerId, minTimestamp: message.timestamp, forceRootGroupIfNotExists: false)
}
var resourceIds: [WrappedMediaResourceId] = []
transaction.deleteMessagesInRange(peerId: id.peerId, namespace: id.namespace, minId: 1, maxId: id.id, forEachMedia: { media in
processRemovedMedia(mediaBox, media)
addMessageMediaResourceIdsToRemove(media: media, resourceIds: &resourceIds)
})
if !resourceIds.isEmpty {
let _ = mediaBox.removeCachedResources(Set(resourceIds)).start()
}
case let .UpdatePeerChatInclusion(peerId, groupId, changedGroup):
let currentInclusion = transaction.getPeerChatListInclusion(peerId)
var currentPinningIndex: UInt16?

View File

@ -4,48 +4,64 @@ import SwiftSignalKit
import SyncCore
private func removeMessageMedia(message: Message, mediaBox: MediaBox) {
for media in message.media {
if let image = media as? TelegramMediaImage {
let _ = mediaBox.removeCachedResources(Set(image.representations.map({ WrappedMediaResourceId($0.resource.id) }))).start()
} else if let file = media as? TelegramMediaFile {
let _ = mediaBox.removeCachedResources(Set(file.previewRepresentations.map({ WrappedMediaResourceId($0.resource.id) }))).start()
let _ = mediaBox.removeCachedResources(Set([WrappedMediaResourceId(file.resource.id)])).start()
func addMessageMediaResourceIdsToRemove(media: Media, resourceIds: inout [WrappedMediaResourceId]) {
if let image = media as? TelegramMediaImage {
for representation in image.representations {
resourceIds.append(WrappedMediaResourceId(representation.resource.id))
}
} else if let file = media as? TelegramMediaFile {
for representation in file.previewRepresentations {
resourceIds.append(WrappedMediaResourceId(representation.resource.id))
}
resourceIds.append(WrappedMediaResourceId(file.resource.id))
}
}
func addMessageMediaResourceIdsToRemove(message: Message, resourceIds: inout [WrappedMediaResourceId]) {
for media in message.media {
addMessageMediaResourceIdsToRemove(media: media, resourceIds: &resourceIds)
}
}
public func deleteMessages(transaction: Transaction, mediaBox: MediaBox, ids: [MessageId], deleteMedia: Bool = true) {
var resourceIds: [WrappedMediaResourceId] = []
if deleteMedia {
for id in ids {
if id.peerId.namespace == Namespaces.Peer.SecretChat {
if let message = transaction.getMessage(id) {
removeMessageMedia(message: message, mediaBox: mediaBox)
addMessageMediaResourceIdsToRemove(message: message, resourceIds: &resourceIds)
}
}
}
}
transaction.deleteMessages(ids, forEachMedia: { media in
if deleteMedia {
processRemovedMedia(mediaBox, media)
}
if !resourceIds.isEmpty {
let _ = mediaBox.removeCachedResources(Set(resourceIds)).start()
}
transaction.deleteMessages(ids, forEachMedia: { _ in
})
}
public func deleteAllMessagesWithAuthor(transaction: Transaction, mediaBox: MediaBox, peerId: PeerId, authorId: PeerId, namespace: MessageId.Namespace) {
var resourceIds: [WrappedMediaResourceId] = []
transaction.removeAllMessagesWithAuthor(peerId, authorId: authorId, namespace: namespace, forEachMedia: { media in
processRemovedMedia(mediaBox, media)
addMessageMediaResourceIdsToRemove(media: media, resourceIds: &resourceIds)
})
if !resourceIds.isEmpty {
let _ = mediaBox.removeCachedResources(Set(resourceIds)).start()
}
}
public func clearHistory(transaction: Transaction, mediaBox: MediaBox, peerId: PeerId, namespaces: MessageIdNamespaces) {
if peerId.namespace == Namespaces.Peer.SecretChat {
var resourceIds: [WrappedMediaResourceId] = []
transaction.withAllMessages(peerId: peerId, { message in
removeMessageMedia(message: message, mediaBox: mediaBox)
addMessageMediaResourceIdsToRemove(message: message, resourceIds: &resourceIds)
return true
})
if !resourceIds.isEmpty {
let _ = mediaBox.removeCachedResources(Set(resourceIds)).start()
}
}
transaction.clearHistory(peerId, namespaces: namespaces, forEachMedia: { media in
processRemovedMedia(mediaBox, media)
transaction.clearHistory(peerId, namespaces: namespaces, forEachMedia: { _ in
})
}

View File

@ -147,9 +147,7 @@ public func clearAuthorHistory(account: Account, peerId: PeerId, memberId: PeerI
|> `catch` { success -> Signal<Void, NoError> in
if success {
return account.postbox.transaction { transaction -> Void in
transaction.removeAllMessagesWithAuthor(peerId, authorId: memberId, namespace: Namespaces.Message.Cloud, forEachMedia: { media in
processRemovedMedia(account.postbox.mediaBox, media)
})
deleteAllMessagesWithAuthor(transaction: transaction, mediaBox: account.postbox.mediaBox, peerId: peerId, authorId: memberId, namespace: Namespaces.Message.Cloud)
}
} else {
return .complete()

View File

@ -1,13 +0,0 @@
import Foundation
import Postbox
import SyncCore
func processRemovedMedia(_ mediaBox: MediaBox, _ media: Media) {
if let image = media as? TelegramMediaImage {
let _ = mediaBox.removeCachedResources(Set(image.representations.map({ WrappedMediaResourceId($0.resource.id) }))).start()
} else if let file = media as? TelegramMediaFile {
let _ = mediaBox.removeCachedResources(Set(file.previewRepresentations.map({ WrappedMediaResourceId($0.resource.id) }))).start()
let _ = mediaBox.removeCachedResources(Set([WrappedMediaResourceId(file.resource.id)])).start()
}
}

View File

@ -104,9 +104,13 @@ func managedApplyPendingScheduledMessagesActions(postbox: Postbox, network: Netw
})
|> then(
postbox.transaction { transaction -> Void in
var resourceIds: [WrappedMediaResourceId] = []
transaction.deleteMessages([entry.id], forEachMedia: { media in
processRemovedMedia(postbox.mediaBox, media)
addMessageMediaResourceIdsToRemove(media: media, resourceIds: &resourceIds)
})
if !resourceIds.isEmpty {
let _ = postbox.mediaBox.removeCachedResources(Set(resourceIds)).start()
}
}
|> ignoreValues
)

View File

@ -421,9 +421,13 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
})
if let minAvailableMessageId = minAvailableMessageId, minAvailableMessageIdUpdated {
var resourceIds: [WrappedMediaResourceId] = []
transaction.deleteMessagesInRange(peerId: peerId, namespace: minAvailableMessageId.namespace, minId: 1, maxId: minAvailableMessageId.id, forEachMedia: { media in
processRemovedMedia(postbox.mediaBox, media)
addMessageMediaResourceIdsToRemove(media: media, resourceIds: &resourceIds)
})
if !resourceIds.isEmpty {
let _ = postbox.mediaBox.removeCachedResources(Set(resourceIds)).start()
}
}
case .chatFull:
break