2.0.0 #92

Merged
defnotken merged 171 commits from 2.0.0 into master 2025-12-21 17:19:36 +00:00
4 changed files with 76 additions and 19 deletions
Showing only changes of commit aa04ab05ab - Show all commits

View File

@@ -469,7 +469,53 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
FileCacheSize = totalSize; FileCacheSize = totalSize;
var maxCacheInBytes = (long)(_configService.Current.MaxLocalCacheInGiB * 1024d * 1024d * 1024d); if (Directory.Exists(_configService.Current.CacheFolder + "/downscaled"))
{
var filesDownscaled = Directory.EnumerateFiles(_configService.Current.CacheFolder + "/downscaled").Select(f => new FileInfo(f)).OrderBy(f => f.LastAccessTime).ToList();
long totalSizeDownscaled = 0;
foreach (var f in filesDownscaled)
{
token.ThrowIfCancellationRequested();
try
{
long size = 0;
if (!isWine)
{
try
{
size = _fileCompactor.GetFileSizeOnDisk(f);
}
catch (Exception ex)
{
Logger.LogTrace(ex, "GetFileSizeOnDisk failed for {file}, using fallback length", f.FullName);
size = f.Length;
}
}
else
{
size = f.Length;
}
totalSizeDownscaled += size;
}
catch (Exception ex)
{
Logger.LogTrace(ex, "Error getting size for {file}", f.FullName);
}
}
FileCacheSize = (totalSize + totalSizeDownscaled);
}
else
{
FileCacheSize = totalSize;
}
var maxCacheInBytes = (long)(_configService.Current.MaxLocalCacheInGiB * 1024d * 1024d * 1024d);
if (FileCacheSize < maxCacheInBytes) if (FileCacheSize < maxCacheInBytes)
return; return;

View File

@@ -4,6 +4,7 @@ using LightlessSync.Services.Compactor;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Win32.SafeHandles; using Microsoft.Win32.SafeHandles;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading.Channels; using System.Threading.Channels;
@@ -16,6 +17,7 @@ public sealed class FileCompactor : IDisposable
public const uint FSCTL_DELETE_EXTERNAL_BACKING = 0x90314U; public const uint FSCTL_DELETE_EXTERNAL_BACKING = 0x90314U;
public const ulong WOF_PROVIDER_FILE = 2UL; public const ulong WOF_PROVIDER_FILE = 2UL;
public const int _maxRetries = 3; public const int _maxRetries = 3;
private readonly bool _isWindows;
private readonly ConcurrentDictionary<string, byte> _pendingCompactions; private readonly ConcurrentDictionary<string, byte> _pendingCompactions;
private readonly ILogger<FileCompactor> _logger; private readonly ILogger<FileCompactor> _logger;
@@ -61,6 +63,7 @@ public sealed class FileCompactor : IDisposable
_logger = logger; _logger = logger;
_lightlessConfigService = lightlessConfigService; _lightlessConfigService = lightlessConfigService;
_dalamudUtilService = dalamudUtilService; _dalamudUtilService = dalamudUtilService;
_isWindows = OperatingSystem.IsWindows();
_compactionQueue = Channel.CreateUnbounded<string>(new UnboundedChannelOptions _compactionQueue = Channel.CreateUnbounded<string>(new UnboundedChannelOptions
{ {
@@ -197,11 +200,10 @@ public sealed class FileCompactor : IDisposable
{ {
try try
{ {
bool isWindowsProc = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
var (_, linuxPath) = ResolvePathsForBtrfs(fileInfo.FullName); var (_, linuxPath) = ResolvePathsForBtrfs(fileInfo.FullName);
var (ok, output, err, code) = var (ok, output, err, code) =
isWindowsProc _isWindows
? RunProcessShell($"stat -c='%b' {QuoteSingle(linuxPath)}", workingDir: null, 10000) ? RunProcessShell($"stat -c='%b' {QuoteSingle(linuxPath)}", workingDir: null, 10000)
: RunProcessDirect("stat", ["-c='%b'", linuxPath], workingDir: null, 10000); : RunProcessDirect("stat", ["-c='%b'", linuxPath], workingDir: null, 10000);
@@ -228,16 +230,28 @@ public sealed class FileCompactor : IDisposable
try try
{ {
var blockSize = GetBlockSizeForPath(fileInfo.FullName, _logger, _dalamudUtilService.IsWine); var blockSize = GetBlockSizeForPath(fileInfo.FullName, _logger, _dalamudUtilService.IsWine);
var losize = GetCompressedFileSizeW(fileInfo.FullName, out uint hosize); if (blockSize <= 0)
var size = (long)hosize << 32 | losize; throw new InvalidOperationException($"Invalid block size {blockSize} for {fileInfo.FullName}");
return (flowControl: false, value: ((size + blockSize - 1) / blockSize) * blockSize);
uint lo = GetCompressedFileSizeW(fileInfo.FullName, out uint hi);
if (lo == 0xFFFFFFFF)
{
int err = Marshal.GetLastWin32Error();
if (err != 0)
throw new Win32Exception(err);
}
long size = ((long)hi << 32) | lo;
long rounded = ((size + blockSize - 1) / blockSize) * blockSize;
return (flowControl: false, value: rounded);
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogDebug(ex, "Failed stat size for {file}, fallback to Length", fileInfo.FullName); _logger.LogDebug(ex, "Failed stat size for {file}, fallback to Length", fileInfo.FullName);
return (flowControl: true, value: default);
} }
return (flowControl: true, value: default);
} }
/// <summary> /// <summary>
@@ -685,7 +699,6 @@ public sealed class FileCompactor : IDisposable
try try
{ {
var (winPath, linuxPath) = ResolvePathsForBtrfs(path); var (winPath, linuxPath) = ResolvePathsForBtrfs(path);
bool isWindowsProc = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
if (IsBtrfsCompressedFile(linuxPath)) if (IsBtrfsCompressedFile(linuxPath))
{ {
@@ -700,7 +713,7 @@ public sealed class FileCompactor : IDisposable
} }
(bool ok, string stdout, string stderr, int code) = (bool ok, string stdout, string stderr, int code) =
isWindowsProc _isWindows
? RunProcessShell($"btrfs filesystem defragment -clzo -- {QuoteSingle(linuxPath)}") ? RunProcessShell($"btrfs filesystem defragment -clzo -- {QuoteSingle(linuxPath)}")
: RunProcessDirect("btrfs", ["filesystem", "defragment", "-clzo", "--", linuxPath]); : RunProcessDirect("btrfs", ["filesystem", "defragment", "-clzo", "--", linuxPath]);
@@ -1029,9 +1042,7 @@ public sealed class FileCompactor : IDisposable
/// <returns></returns> /// <returns></returns>
private (string windowsPath, string linuxPath) ResolvePathsForBtrfs(string path) private (string windowsPath, string linuxPath) ResolvePathsForBtrfs(string path)
{ {
bool isWindowsProc = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); if (!_isWindows)
if (!isWindowsProc)
return (path, path); return (path, path);
var (ok, outp, _, _) = RunProcessShell($"winepath -u {QuoteSingle(path)}", workingDir: null, 5000); var (ok, outp, _, _) = RunProcessShell($"winepath -u {QuoteSingle(path)}", workingDir: null, 5000);
@@ -1050,7 +1061,7 @@ public sealed class FileCompactor : IDisposable
{ {
try try
{ {
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (_isWindows)
{ {
using var _ = new FileStream(winePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); using var _ = new FileStream(winePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
} }

View File

@@ -179,9 +179,9 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
int i = 0; int i = 0;
double dblSByte = bytes; double dblSByte = bytes;
while (dblSByte >= 1000 && i < suffix.Length - 1) while (dblSByte >= 1024 && i < suffix.Length - 1)
{ {
dblSByte /= 1000.0; dblSByte /= 1024.0;
i++; i++;
} }

View File

@@ -32,7 +32,7 @@ namespace LightlessSync.Utils
{ {
string rootPath; string rootPath;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && (!IsProbablyWine() || !isWine)) if (OperatingSystem.IsWindows() && (!IsProbablyWine() || !isWine))
{ {
var info = new FileInfo(filePath); var info = new FileInfo(filePath);
var dir = info.Directory ?? new DirectoryInfo(filePath); var dir = info.Directory ?? new DirectoryInfo(filePath);
@@ -50,7 +50,7 @@ namespace LightlessSync.Utils
FilesystemType detected; FilesystemType detected;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && (!IsProbablyWine() || !isWine)) if (OperatingSystem.IsWindows() && (!IsProbablyWine() || !isWine))
{ {
var root = new DriveInfo(rootPath); var root = new DriveInfo(rootPath);
var format = root.DriveFormat?.ToUpperInvariant() ?? string.Empty; var format = root.DriveFormat?.ToUpperInvariant() ?? string.Empty;
@@ -214,7 +214,7 @@ namespace LightlessSync.Utils
if (_blockSizeCache.TryGetValue(root, out int cached)) if (_blockSizeCache.TryGetValue(root, out int cached))
return cached; return cached;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !isWine) if (OperatingSystem.IsWindows() && !isWine)
{ {
int result = GetDiskFreeSpaceW(root, int result = GetDiskFreeSpaceW(root,
out uint sectorsPerCluster, out uint sectorsPerCluster,