From f1e636a79dbff40fa90ef5d368d39be715edca72 Mon Sep 17 00:00:00 2001 From: acite <1498045907@qq.com> Date: Sat, 20 Sep 2025 15:03:05 +0800 Subject: [PATCH] [optimize] Database optimizition --- .idea/.idea.Abyss/.idea/workspace.xml | 7 +- Abyss.sln | 6 -- Abyss/Components/Services/ResourceService.cs | 92 +++++++++----------- 3 files changed, 46 insertions(+), 59 deletions(-) diff --git a/.idea/.idea.Abyss/.idea/workspace.xml b/.idea/.idea.Abyss/.idea/workspace.xml index 943dece..daf4c55 100644 --- a/.idea/.idea.Abyss/.idea/workspace.xml +++ b/.idea/.idea.Abyss/.idea/workspace.xml @@ -11,7 +11,8 @@ - + + diff --git a/Abyss.sln b/Abyss.sln index a2abd49..08c5c17 100644 --- a/Abyss.sln +++ b/Abyss.sln @@ -2,8 +2,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Abyss", "Abyss\Abyss.csproj", "{3337C1CD-2419-4922-BC92-AF1A825DDF23}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AbyssCli", "AbyssCli\AbyssCli.csproj", "{D7D668D4-61E7-4AA4-B615-A162FABAD333}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -14,9 +12,5 @@ Global {3337C1CD-2419-4922-BC92-AF1A825DDF23}.Debug|Any CPU.Build.0 = Debug|Any CPU {3337C1CD-2419-4922-BC92-AF1A825DDF23}.Release|Any CPU.ActiveCfg = Release|Any CPU {3337C1CD-2419-4922-BC92-AF1A825DDF23}.Release|Any CPU.Build.0 = Release|Any CPU - {D7D668D4-61E7-4AA4-B615-A162FABAD333}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D7D668D4-61E7-4AA4-B615-A162FABAD333}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D7D668D4-61E7-4AA4-B615-A162FABAD333}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D7D668D4-61E7-4AA4-B615-A162FABAD333}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/Abyss/Components/Services/ResourceService.cs b/Abyss/Components/Services/ResourceService.cs index bcfe76d..3954a90 100644 --- a/Abyss/Components/Services/ResourceService.cs +++ b/Abyss/Components/Services/ResourceService.cs @@ -531,7 +531,8 @@ public class ResourceService } else { - _logger.LogDebug($"Query: access denied or not managed for '{entry}' (user token: {token}) - item skipped."); + _logger.LogDebug( + $"Query: access denied or not managed for '{entry}' (user token: {token}) - item skipped."); } } catch (Exception exEntry) @@ -788,33 +789,32 @@ public class ResourceService return false; } - // Normalize path to full path (Valid / ValidAll expect absolute path starting with media root) + // Normalize path to full path path = Path.GetFullPath(path); - // If recursive and path is directory, collect all descendants (iterative) + // Collect targets and permission checks List targets = new List(); try { if (recursive && Directory.Exists(path)) { - // include root directory itself + _logger.LogInformation($"Recursive directory '{path}'."); targets.Add(path); - // Enumerate all files and directories under path iteratively foreach (var entry in Directory.EnumerateFileSystemEntries(path, "*", SearchOption.AllDirectories)) { targets.Add(entry); } - // Permission check for all targets if (!await ValidAll(targets.ToArray(), token, OperationType.Security, ip)) { _logger.LogWarning($"Permission denied for recursive chmod on '{path}'"); return false; } + + _logger.LogInformation($"Successfully validated chmod on '{path}'."); } else { - // Non-recursive or target is a file: validate single path if (!await Valid(path, token, OperationType.Security, ip)) { _logger.LogWarning($"Permission denied for chmod on '{path}'"); @@ -824,8 +824,9 @@ public class ResourceService targets.Add(path); } - // Convert targets to relative paths and UIDs - var relUids = targets.Select(t => Path.GetRelativePath(_config.MediaRoot, t)) + // Build distinct UIDs + var relUids = targets + .Select(t => Path.GetRelativePath(_config.MediaRoot, t)) .Select(rel => Uid(rel)) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); @@ -836,35 +837,28 @@ public class ResourceService return false; } - // Batch query existing ResourceAttribute rows for these UIDs (chunk to respect SQLite param limit) - var rows = new List(); - const int sqliteMaxVariableNumber = 900; + // Chunked bulk UPDATE using SQL "UPDATE ... WHERE Uid IN (...)" + int updatedCount = 0; + const int sqliteMaxVariableNumber = 900; // leave some headroom for other params for (int i = 0; i < relUids.Count; i += sqliteMaxVariableNumber) { var chunk = relUids.Skip(i).Take(sqliteMaxVariableNumber).ToList(); var placeholders = string.Join(",", chunk.Select(_ => "?")); - var queryArgs = chunk.Cast().ToArray(); - var sql = $"SELECT * FROM ResourceAttributes WHERE Uid IN ({placeholders})"; - var chunkResult = await _database.QueryAsync(sql, queryArgs); - rows.AddRange(chunkResult); - } + // First param is permission, rest are Uid values + var args = new List { permission }; + args.AddRange(chunk); - var rowDict = rows.ToDictionary(r => r.Uid, StringComparer.OrdinalIgnoreCase); - - int updatedCount = 0; - foreach (var uid in relUids) - { - if (rowDict.TryGetValue(uid, out var ra)) + var sql = $"UPDATE ResourceAttributes SET Permission = ? WHERE Uid IN ({placeholders})"; + try { - ra.Permission = permission; - var res = await _database.UpdateAsync(ra); - if (res > 0) updatedCount++; - else _logger.LogError($"Failed to update permission row (UID={uid}) for chmod on '{path}'"); + var rowsAffected = await _database.ExecuteAsync(sql, args.ToArray()); + updatedCount += rowsAffected; + _logger.LogInformation($"Chmod chunk updated {rowsAffected} rows (chunk size {chunk.Count})."); } - else + catch (Exception ex) { - // Resource not managed by DB — skip but log - _logger.LogWarning($"Chmod skipped: resource not found in DB (Uid={uid}) for target '{path}'"); + _logger.LogError(ex, $"Error executing chmod update chunk for path '{path}'."); + // continue with other chunks; do not abort whole operation on one chunk error } } @@ -929,8 +923,9 @@ public class ResourceService targets.Add(path); } - // Build UID list - var relUids = targets.Select(t => Path.GetRelativePath(_config.MediaRoot, t)) + // Build distinct UIDs + var relUids = targets + .Select(t => Path.GetRelativePath(_config.MediaRoot, t)) .Select(rel => Uid(rel)) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); @@ -941,34 +936,27 @@ public class ResourceService return false; } - // Batch query DB - var rows = new List(); + // Chunked bulk UPDATE: SET Owner = ? WHERE Uid IN (...) + int updatedCount = 0; const int sqliteMaxVariableNumber = 900; for (int i = 0; i < relUids.Count; i += sqliteMaxVariableNumber) { var chunk = relUids.Skip(i).Take(sqliteMaxVariableNumber).ToList(); var placeholders = string.Join(",", chunk.Select(_ => "?")); - var queryArgs = chunk.Cast().ToArray(); - var sql = $"SELECT * FROM ResourceAttributes WHERE Uid IN ({placeholders})"; - var chunkResult = await _database.QueryAsync(sql, queryArgs); - rows.AddRange(chunkResult); - } + var args = new List { owner }; + args.AddRange(chunk); - var rowDict = rows.ToDictionary(r => r.Uid, StringComparer.OrdinalIgnoreCase); - - int updatedCount = 0; - foreach (var uid in relUids) - { - if (rowDict.TryGetValue(uid, out var ra)) + var sql = $"UPDATE ResourceAttributes SET Owner = ? WHERE Uid IN ({placeholders})"; + try { - ra.Owner = owner; - var res = await _database.UpdateAsync(ra); - if (res > 0) updatedCount++; - else _logger.LogError($"Failed to update owner row (UID={uid}) for chown on '{path}'"); + var rowsAffected = await _database.ExecuteAsync(sql, args.ToArray()); + updatedCount += rowsAffected; + _logger.LogInformation($"Chown chunk updated {rowsAffected} rows (chunk size {chunk.Count})."); } - else + catch (Exception ex) { - _logger.LogWarning($"Chown skipped: resource not found in DB (Uid={uid}) for target '{path}'"); + _logger.LogError(ex, $"Error executing chown update chunk for path '{path}'."); + // continue with remaining chunks } } @@ -1019,7 +1007,7 @@ public class ResourceService }) == 1; } } - + public async Task GetAttribute(string path) { try