Assorted updates and bug fixes

This commit is contained in:
Ali
2020-11-10 21:04:52 +04:00
2556 changed files with 1593872 additions and 329995 deletions

View File

@@ -2,34 +2,119 @@ import Foundation
import SwiftSignalKit
private typealias SignalKitTimer = SwiftSignalKit.Timer
struct InodeInfo {
var inode: __darwin_ino64_t
var timestamp: Int32
var size: UInt32
}
private func scanFiles(at path: String, olderThan minTimestamp: Int32, anyway: ((String, Int, Int32)) -> Void, unlink f: (String) -> Void) {
guard let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: path), includingPropertiesForKeys: [.contentModificationDateKey, .isDirectoryKey, .fileSizeKey], options: [.skipsSubdirectoryDescendants], errorHandler: nil) else {
private struct ScanFilesResult {
var unlinkedCount = 0
var totalSize: UInt64 = 0
}
private func scanFiles(at path: String, olderThan minTimestamp: Int32, inodes: inout [InodeInfo]) -> ScanFilesResult {
var result = ScanFilesResult()
if let dp = opendir(path) {
let pathBuffer = malloc(2048).assumingMemoryBound(to: Int8.self)
defer {
free(pathBuffer)
}
while true {
guard let dirp = readdir(dp) else {
break
}
if strncmp(&dirp.pointee.d_name.0, ".", 1024) == 0 {
continue
}
if strncmp(&dirp.pointee.d_name.0, "..", 1024) == 0 {
continue
}
strncpy(pathBuffer, path, 1024)
strncat(pathBuffer, "/", 1024)
strncat(pathBuffer, &dirp.pointee.d_name.0, 1024)
//puts(pathBuffer)
//puts("\n")
var value = stat()
if stat(pathBuffer, &value) == 0 {
if value.st_mtimespec.tv_sec < minTimestamp {
unlink(pathBuffer)
result.unlinkedCount += 1
} else {
result.totalSize += UInt64(value.st_size)
inodes.append(InodeInfo(
inode: value.st_ino,
timestamp: Int32(clamping: value.st_mtimespec.tv_sec),
size: UInt32(clamping: value.st_size)
))
}
}
}
closedir(dp)
}
return result
}
private func mapFiles(paths: [String], inodes: inout [InodeInfo], removeSize: UInt64) {
var removedSize: UInt64 = 0
inodes.sort(by: { lhs, rhs in
return lhs.timestamp < rhs.timestamp
})
var inodesToDelete = Set<__darwin_ino64_t>()
for inode in inodes {
inodesToDelete.insert(inode.inode)
removedSize += UInt64(inode.size)
if removedSize >= removeSize {
break
}
}
if inodesToDelete.isEmpty {
return
}
while let item = enumerator.nextObject() {
guard let url = item as? NSURL else {
continue
}
guard let resourceValues = try? url.resourceValues(forKeys: [.contentModificationDateKey, .isDirectoryKey, .fileSizeKey]) else {
continue
}
if let value = resourceValues[.isDirectoryKey] as? Bool, value {
continue
}
if let value = resourceValues[.contentModificationDateKey] as? NSDate {
var unlinked = false
if Int32(value.timeIntervalSince1970) < minTimestamp {
if let file = url.path {
f(file)
unlinked = true
}
}
if let file = url.path, !unlinked {
if let size = (resourceValues[.fileSizeKey] as? NSNumber)?.intValue {
anyway((file, size, Int32(value.timeIntervalSince1970)))
let pathBuffer = malloc(2048).assumingMemoryBound(to: Int8.self)
defer {
free(pathBuffer)
}
for path in paths {
if let dp = opendir(path) {
while true {
guard let dirp = readdir(dp) else {
break
}
if strncmp(&dirp.pointee.d_name.0, ".", 1024) == 0 {
continue
}
if strncmp(&dirp.pointee.d_name.0, "..", 1024) == 0 {
continue
}
strncpy(pathBuffer, path, 1024)
strncat(pathBuffer, "/", 1024)
strncat(pathBuffer, &dirp.pointee.d_name.0, 1024)
//puts(pathBuffer)
//puts("\n")
var value = stat()
if stat(pathBuffer, &value) == 0 {
if inodesToDelete.contains(value.st_ino) {
unlink(pathBuffer)
}
}
}
closedir(dp)
}
}
}
@@ -89,49 +174,42 @@ private final class TimeBasedCleanupImpl {
var removedShortLivedCount: Int = 0
var removedGeneralCount: Int = 0
var removedGeneralLimitCount: Int = 0
let startTime = CFAbsoluteTimeGetCurrent()
var inodes: [InodeInfo] = []
var paths: [String] = []
let timestamp = Int32(Date().timeIntervalSince1970)
let bytesLimit = UInt64(gigabytesLimit) * 1024 * 1024 * 1024
let oldestShortLivedTimestamp = timestamp - shortLived
let oldestGeneralTimestamp = timestamp - general
for path in shortLivedPaths {
scanFiles(at: path, olderThan: oldestShortLivedTimestamp, anyway: { _, _, _ in
}, unlink: { file in
removedShortLivedCount += 1
unlink(file)
})
let scanResult = scanFiles(at: path, olderThan: oldestShortLivedTimestamp, inodes: &inodes)
if !paths.contains(path) {
paths.append(path)
}
removedShortLivedCount += scanResult.unlinkedCount
}
var checkFiles: [GeneralFile] = []
var totalLimitSize: UInt64 = 0
for path in generalPaths {
scanFiles(at: path, olderThan: oldestGeneralTimestamp, anyway: { file, size, timestamp in
checkFiles.append(GeneralFile(file: file, size: size, timestamp: timestamp))
totalLimitSize += UInt64(size)
}, unlink: { file in
removedGeneralCount += 1
unlink(file)
})
let scanResult = scanFiles(at: path, olderThan: oldestGeneralTimestamp, inodes: &inodes)
if !paths.contains(path) {
paths.append(path)
}
removedGeneralCount += scanResult.unlinkedCount
totalLimitSize += scanResult.totalSize
}
clear: for item in checkFiles.sorted(by: <) {
if totalLimitSize > bytesLimit {
unlink(item.file)
removedGeneralLimitCount += 1
if totalLimitSize > UInt64(item.size) {
totalLimitSize -= UInt64(item.size)
} else {
totalLimitSize = 0
}
} else {
break clear
}
if totalLimitSize > bytesLimit {
mapFiles(paths: paths, inodes: &inodes, removeSize: totalLimitSize - bytesLimit)
}
if removedShortLivedCount != 0 || removedGeneralCount != 0 || removedGeneralLimitCount != 0 {
print("[TimeBasedCleanup] removed \(removedShortLivedCount) short-lived files, \(removedGeneralCount) general files, \(removedGeneralLimitCount) limit files")
print("[TimeBasedCleanup] \(CFAbsoluteTimeGetCurrent() - startTime) s removed \(removedShortLivedCount) short-lived files, \(removedGeneralCount) general files, \(removedGeneralLimitCount) limit files")
}
subscriber.putCompletion()
}