From 0c0b519072b53e9e9805276aeb7eeb5714d65d6e Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Thu, 3 Sep 2020 00:58:07 +0100 Subject: [PATCH] Move root directory cache to VFS. --- RomRepoMgr.Core/Filesystem/Fuse.cs | 84 ++++++++---------------------- RomRepoMgr.Core/Filesystem/Vfs.cs | 70 ++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 65 deletions(-) diff --git a/RomRepoMgr.Core/Filesystem/Fuse.cs b/RomRepoMgr.Core/Filesystem/Fuse.cs index 7b0710f..22516cb 100644 --- a/RomRepoMgr.Core/Filesystem/Fuse.cs +++ b/RomRepoMgr.Core/Filesystem/Fuse.cs @@ -27,14 +27,12 @@ namespace RomRepoMgr.Core.Filesystem readonly ConcurrentDictionary _streamsCache; readonly Vfs _vfs; long _lastHandle; - ConcurrentDictionary _rootDirectoryCache; string _umountToken; public Fuse(Vfs vfs) { _directoryCache = new ConcurrentDictionary>(); _lastHandle = 0; - _rootDirectoryCache = new ConcurrentDictionary(); _machinesStatCache = new ConcurrentDictionary>(); _romSetsCache = new ConcurrentDictionary(); _machineFilesCache = new ConcurrentDictionary>(); @@ -106,30 +104,27 @@ namespace RomRepoMgr.Core.Filesystem return 0; } - if(_rootDirectoryCache.Count == 0) - FillRootDirectoryCache(); + long romSetId = _vfs.GetRomSetId(pieces[0]); - if(!_rootDirectoryCache.TryGetValue(pieces[0], out long romSetId)) + if(romSetId <= 0) { - if(pieces[0] == ".fuse_umount" && - _umountToken != null) + if(pieces[0] != ".fuse_umount" || + _umountToken == null) + return Errno.ENOENT; + + stat = new Stat { - stat = new Stat - { - st_mode = FilePermissions.S_IFREG | NativeConvert.FromOctalPermissionString("0444"), - st_nlink = 1, - st_ctime = NativeConvert.ToTimeT(DateTime.UtcNow), - st_mtime = NativeConvert.ToTimeT(DateTime.UtcNow), - st_blksize = 0, - st_blocks = 0, - st_ino = 0, - st_size = 0 - }; + st_mode = FilePermissions.S_IFREG | NativeConvert.FromOctalPermissionString("0444"), + st_nlink = 1, + st_ctime = NativeConvert.ToTimeT(DateTime.UtcNow), + st_mtime = NativeConvert.ToTimeT(DateTime.UtcNow), + st_blksize = 0, + st_blocks = 0, + st_ino = 0, + st_size = 0 + }; - return 0; - } - - return Errno.ENOENT; + return 0; } if(!_romSetsCache.TryGetValue(romSetId, out RomSet romSet)) @@ -808,40 +803,6 @@ namespace RomRepoMgr.Core.Filesystem protected override Errno OnRemovePathExtendedAttribute(string path, string name) => Errno.EROFS; - void FillRootDirectoryCache() - { - using var ctx = Context.Create(Settings.Settings.Current.DatabasePath); - - List entries = new List - { - new DirectoryEntry("."), - new DirectoryEntry("..") - }; - - ConcurrentDictionary rootCache = new ConcurrentDictionary(); - - foreach(RomSet set in ctx.RomSets) - { - string name = set.Name.Replace('/', '∕'); - - if(entries.Any(e => e.Name == name)) - name = Path.GetFileNameWithoutExtension(set.Filename)?.Replace('/', '∕'); - - if(entries.Any(e => e.Name == name) || - name == null) - name = Path.GetFileNameWithoutExtension(set.Sha384); - - if(name == null) - continue; - - entries.Add(new DirectoryEntry(name)); - rootCache[name] = set.Id; - _romSetsCache[set.Id] = set; - } - - _rootDirectoryCache = rootCache; - } - protected override Errno OnOpenDirectory(string directory, OpenedPathInfo info) { try @@ -881,7 +842,6 @@ namespace RomRepoMgr.Core.Filesystem info.Handle = new IntPtr(_lastHandle); _directoryCache[_lastHandle] = entries; - _rootDirectoryCache = rootCache; return 0; } @@ -891,10 +851,9 @@ namespace RomRepoMgr.Core.Filesystem if(pieces.Length == 0) return Errno.ENOENT; - if(_rootDirectoryCache.Count == 0) - FillRootDirectoryCache(); + long romSetId = _vfs.GetRomSetId(pieces[0]); - if(!_rootDirectoryCache.TryGetValue(pieces[0], out long romSetId)) + if(romSetId <= 0) return Errno.ENOENT; if(!_romSetsCache.TryGetValue(romSetId, out RomSet romSet)) @@ -1076,10 +1035,9 @@ namespace RomRepoMgr.Core.Filesystem if(pieces.Length == 0) return mode.HasFlag(AccessModes.W_OK) ? Errno.EROFS : 0; - if(_rootDirectoryCache.Count == 0) - FillRootDirectoryCache(); + long romSetId = _vfs.GetRomSetId(pieces[0]); - if(!_rootDirectoryCache.TryGetValue(pieces[0], out long romSetId)) + if(romSetId <= 0) return Errno.ENOENT; if(!_romSetsCache.TryGetValue(romSetId, out RomSet romSet)) diff --git a/RomRepoMgr.Core/Filesystem/Vfs.cs b/RomRepoMgr.Core/Filesystem/Vfs.cs index 925ed16..f77fd98 100644 --- a/RomRepoMgr.Core/Filesystem/Vfs.cs +++ b/RomRepoMgr.Core/Filesystem/Vfs.cs @@ -1,15 +1,27 @@ using System; +using System.Collections.Concurrent; +using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Threading.Tasks; using RomRepoMgr.Database; +using RomRepoMgr.Database.Models; namespace RomRepoMgr.Core.Filesystem { public class Vfs : IDisposable { - Fuse _fuse; - Winfsp _winfsp; + readonly ConcurrentDictionary _romSetsCache; + Fuse _fuse; + + ConcurrentDictionary _rootDirectoryCache; + Winfsp _winfsp; + + public Vfs() + { + _rootDirectoryCache = new ConcurrentDictionary(); + _romSetsCache = new ConcurrentDictionary(); + } public static bool IsAvailable => Winfsp.IsAvailable || Fuse.IsAvailable; @@ -69,5 +81,59 @@ namespace RomRepoMgr.Core.Filesystem internal string[] SplitPath(string path) => path.Split(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "\\" : "/", StringSplitOptions.RemoveEmptyEntries); + + void FillRootDirectoryCache() + { + using var ctx = Context.Create(Settings.Settings.Current.DatabasePath); + + ConcurrentDictionary rootCache = new ConcurrentDictionary(); + + foreach(RomSet set in ctx.RomSets) + { + string name; + + if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + name = set.Name.Replace('/', '∕').Replace('<', '\uFF1C').Replace('>', '\uFF1E'). + Replace(':', '\uFF1A').Replace('"', '\u2033').Replace('\\', '\').Replace('|', '|'). + Replace('?', '?').Replace('*', '*'); + + if(rootCache.ContainsKey(name)) + name = Path.GetFileNameWithoutExtension(set.Filename)?.Replace('/', '∕').Replace('<', '\uFF1C'). + Replace('>', '\uFF1E').Replace(':', '\uFF1A').Replace('"', '\u2033'). + Replace('\\', '\').Replace('|', '|').Replace('?', '?').Replace('*', '*'); + } + else + { + name = set.Name.Replace('/', '∕'); + + if(rootCache.ContainsKey(name)) + name = Path.GetFileNameWithoutExtension(set.Filename)?.Replace('/', '∕'); + } + + if(name == null || + rootCache.ContainsKey(name)) + name = Path.GetFileNameWithoutExtension(set.Sha384); + + if(name == null) + continue; + + rootCache[name] = set.Id; + _romSetsCache[set.Id] = set; + } + + _rootDirectoryCache = rootCache; + } + + internal long GetRomSetId(string name) + { + if(_rootDirectoryCache.Count == 0) + FillRootDirectoryCache(); + + if(!_rootDirectoryCache.TryGetValue(name, out long romSetId)) + return -1; + + return romSetId; + } } } \ No newline at end of file