From 1249733d95763f4ff66b674092e77d53c62de982 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Mon, 9 Jan 2023 00:35:14 +0400 Subject: [PATCH] Don't perform directory mapping if the total size does not exceed the limit --- submodules/Postbox/BUILD | 1 + .../Postbox/Sources/TimeBasedCleanup.swift | 63 +++++++++++++++++-- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/submodules/Postbox/BUILD b/submodules/Postbox/BUILD index d9ce7c24b3..a86c579b54 100644 --- a/submodules/Postbox/BUILD +++ b/submodules/Postbox/BUILD @@ -18,6 +18,7 @@ swift_library( "//submodules/ManagedFile:ManagedFile", "//submodules/Utils/RangeSet:RangeSet", "//submodules/CryptoUtils", + "//submodules/Utils/DarwinDirStat", ], visibility = [ "//visibility:public", diff --git a/submodules/Postbox/Sources/TimeBasedCleanup.swift b/submodules/Postbox/Sources/TimeBasedCleanup.swift index 019f2e4c88..e541be9216 100644 --- a/submodules/Postbox/Sources/TimeBasedCleanup.swift +++ b/submodules/Postbox/Sources/TimeBasedCleanup.swift @@ -1,5 +1,7 @@ import Foundation import SwiftSignalKit +import DarwinDirStat + private typealias SignalKitTimer = SwiftSignalKit.Timer struct InodeInfo { @@ -127,7 +129,7 @@ private final class TempScanDatabase { } } -private func scanFiles(at path: String, olderThan minTimestamp: Int32, includeSubdirectories: Bool, tempDatabase: TempScanDatabase) -> ScanFilesResult { +private func scanFiles(at path: String, olderThan minTimestamp: Int32, includeSubdirectories: Bool, performSizeMapping: Bool, tempDatabase: TempScanDatabase) -> ScanFilesResult { var result = ScanFilesResult() if let dp = opendir(path) { @@ -156,7 +158,7 @@ private func scanFiles(at path: String, olderThan minTimestamp: Int32, includeSu if (((value.st_mode) & S_IFMT) == S_IFDIR) { if includeSubdirectories { if let subPath = String(data: Data(bytes: pathBuffer, count: strnlen(pathBuffer, 1024)), encoding: .utf8) { - let subResult = scanFiles(at: subPath, olderThan: minTimestamp, includeSubdirectories: true, tempDatabase: tempDatabase) + let subResult = scanFiles(at: subPath, olderThan: minTimestamp, includeSubdirectories: true, performSizeMapping: performSizeMapping, tempDatabase: tempDatabase) result.totalSize += subResult.totalSize result.unlinkedCount += subResult.unlinkedCount } @@ -167,7 +169,9 @@ private func scanFiles(at path: String, olderThan minTimestamp: Int32, includeSu result.unlinkedCount += 1 } else { result.totalSize += UInt64(value.st_size) - tempDatabase.add(pathBuffer: pathBuffer, pathSize: strnlen(pathBuffer, 1024), size: Int64(value.st_size), timestamp: Int32(value.st_mtimespec.tv_sec)) + if performSizeMapping { + tempDatabase.add(pathBuffer: pathBuffer, pathSize: strnlen(pathBuffer, 1024), size: Int64(value.st_size), timestamp: Int32(value.st_mtimespec.tv_sec)) + } } } } @@ -259,6 +263,21 @@ private func scanFiles(at path: String, olderThan minTimestamp: Int32, includeSu } }*/ +private func statForDirectory(path: String) -> Int64 { + var s = darwin_dirstat() + var result = dirstat_np(path, 1, &s, MemoryLayout.size) + if result != -1 { + return Int64(s.total_size) + } else { + result = dirstat_np(path, 0, &s, MemoryLayout.size) + if result != -1 { + return Int64(s.total_size) + } else { + return 0 + } + } +} + private final class TimeBasedCleanupImpl { private let queue: Queue private let storageBox: StorageBox @@ -329,10 +348,42 @@ private final class TimeBasedCleanupImpl { let bytesLimit = UInt64(gigabytesLimit) * 1024 * 1024 * 1024 //#endif + var totalApproximateSize: Int64 = 0 + for path in shortLivedPaths { + totalApproximateSize += statForDirectory(path: path) + } + for path in generalPaths { + totalApproximateSize += statForDirectory(path: path) + } + + if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: totalSizeBasedPath), includingPropertiesForKeys: [.fileSizeKey, .fileResourceIdentifierKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) { + var fileIds = Set() + loop: for url in enumerator { + guard let url = url as? URL else { + continue + } + if let fileId = (try? url.resourceValues(forKeys: Set([.fileResourceIdentifierKey])))?.fileResourceIdentifier as? Data { + if fileIds.contains(fileId) { + continue loop + } + + if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 { + fileIds.insert(fileId) + totalApproximateSize += Int64(value) + } + } + } + } + + var performSizeMapping = true + if totalApproximateSize <= gigabytesLimit { + performSizeMapping = false + } + let oldestShortLivedTimestamp = timestamp - shortLived let oldestGeneralTimestamp = timestamp - general for path in shortLivedPaths { - let scanResult = scanFiles(at: path, olderThan: oldestShortLivedTimestamp, includeSubdirectories: true, tempDatabase: tempDatabase) + let scanResult = scanFiles(at: path, olderThan: oldestShortLivedTimestamp, includeSubdirectories: true, performSizeMapping: performSizeMapping, tempDatabase: tempDatabase) if !paths.contains(path) { paths.append(path) } @@ -342,7 +393,7 @@ private final class TimeBasedCleanupImpl { var totalLimitSize: UInt64 = 0 for path in generalPaths { - let scanResult = scanFiles(at: path, olderThan: oldestGeneralTimestamp, includeSubdirectories: true, tempDatabase: tempDatabase) + let scanResult = scanFiles(at: path, olderThan: oldestGeneralTimestamp, includeSubdirectories: true, performSizeMapping: performSizeMapping, tempDatabase: tempDatabase) if !paths.contains(path) { paths.append(path) } @@ -350,7 +401,7 @@ private final class TimeBasedCleanupImpl { totalLimitSize += scanResult.totalSize } do { - let scanResult = scanFiles(at: totalSizeBasedPath, olderThan: 0, includeSubdirectories: false, tempDatabase: tempDatabase) + let scanResult = scanFiles(at: totalSizeBasedPath, olderThan: 0, includeSubdirectories: false, performSizeMapping: performSizeMapping, tempDatabase: tempDatabase) if !paths.contains(totalSizeBasedPath) { paths.append(totalSizeBasedPath) }