Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance of watcher, operations and props loading #6028

Merged
merged 25 commits into from
Sep 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions Files/DataModels/FilesystemItemsOperationDataModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Files.Helpers;
using Files.ViewModels.Dialogs;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
Expand Down Expand Up @@ -59,16 +60,16 @@ public FilesystemItemsOperationDataModel(FilesystemOperationType operationType,

public async Task<List<FilesystemOperationItemViewModel>> ToItems(Action updatePrimaryButtonEnabled, Action optionGenerateNewName, Action optionReplaceExisting, Action optionSkip)
{
List<FilesystemOperationItemViewModel> items = new List<FilesystemOperationItemViewModel>();
ConcurrentBag<(int Index, FilesystemOperationItemViewModel Model)> items = new ConcurrentBag<(int Index, FilesystemOperationItemViewModel Model)>();

List<FilesystemItemsOperationItemModel> nonConflictingItems = IncomingItems.Except(ConflictingItems).ToList();

// Add conflicting items first
foreach (var item in ConflictingItems)
await Task.WhenAll(ConflictingItems.Select(async (item, index) =>
{
var iconData = await FileThumbnailHelper.LoadIconFromPathAsync(item.SourcePath, 64u, Windows.Storage.FileProperties.ThumbnailMode.ListView);

items.Add(new FilesystemOperationItemViewModel(updatePrimaryButtonEnabled, optionGenerateNewName, optionReplaceExisting, optionSkip)
items.Add((index, new FilesystemOperationItemViewModel(updatePrimaryButtonEnabled, optionGenerateNewName, optionReplaceExisting, optionSkip)
{
IsConflict = true,
ItemIcon = iconData != null ? await iconData.ToBitmapAsync() : null,
Expand All @@ -78,15 +79,17 @@ public async Task<List<FilesystemOperationItemViewModel>> ToItems(Action updateP
ConflictResolveOption = FileNameConflictResolveOptionType.GenerateNewName,
ItemOperation = item.OperationType,
ActionTaken = false
});
}
}));
}));

var baseIndex = ConflictingItems.Count;

// Then add non-conflicting items
foreach (var item in nonConflictingItems)
await Task.WhenAll(nonConflictingItems.Select(async (item, index) =>
{
var iconData = await FileThumbnailHelper.LoadIconFromPathAsync(item.SourcePath, 64u, Windows.Storage.FileProperties.ThumbnailMode.ListView);

items.Add(new FilesystemOperationItemViewModel(updatePrimaryButtonEnabled, optionGenerateNewName, optionReplaceExisting, optionSkip)
items.Add((baseIndex + index, new FilesystemOperationItemViewModel(updatePrimaryButtonEnabled, optionGenerateNewName, optionReplaceExisting, optionSkip)
{
IsConflict = false,
ItemIcon = iconData != null ? await iconData.ToBitmapAsync() : null,
Expand All @@ -96,10 +99,10 @@ public async Task<List<FilesystemOperationItemViewModel>> ToItems(Action updateP
ConflictResolveOption = FileNameConflictResolveOptionType.NotAConflict,
ItemOperation = item.OperationType,
ActionTaken = true
});
}
}));
}));

return items;
return items.OrderBy(i => i.Index).Select(i => i.Model).ToList();
}

private string GetOperationIconGlyph(FilesystemOperationType operationType)
Expand Down
2 changes: 1 addition & 1 deletion Files/Files.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,6 @@
<Compile Include="Helpers\Extension.cs" />
<Compile Include="Helpers\FileListCache\FileListCacheController.cs" />
<Compile Include="Helpers\FileListCache\IFileListCache.cs" />
<Compile Include="Helpers\FileListCache\PersistentSQLiteCacheAdapter.cs" />
<Compile Include="Helpers\ExtensionManager.cs" />
<Compile Include="Helpers\IntervalSampler.cs" />
<Compile Include="Helpers\QuickLookHelpers.cs" />
Expand All @@ -275,6 +274,7 @@
<Compile Include="Helpers\SidebarHelpers.cs" />
<Compile Include="Helpers\XamlHelpers\DependencyObjectHelpers.cs" />
<Compile Include="Helpers\XamlHelpers\SystemTypeToXaml.cs" />
<Compile Include="Helpers\AsyncManualResetEvent.cs" />
<Compile Include="IBaseLayout.cs" />
<Compile Include="Interacts\BaseLayoutCommandImplementationModel.cs" />
<Compile Include="Interacts\BaseLayoutCommandsViewModel.cs" />
Expand Down
12 changes: 11 additions & 1 deletion Files/Filesystem/ListedItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using Windows.Storage;
using Windows.UI.Xaml.Media.Imaging;

Expand All @@ -22,7 +23,16 @@ public class ListedItem : ObservableObject, IGroupableItem
{
public bool IsHiddenItem { get; set; } = false;
public StorageItemTypes PrimaryItemAttribute { get; set; }
public bool ItemPropertiesInitialized { get; set; } = false;

private volatile int itemPropertiesInitialized = 0;
public bool ItemPropertiesInitialized
{
get => itemPropertiesInitialized == 1;
set
{
Interlocked.Exchange(ref itemPropertiesInitialized, value ? 1 : 0);
}
}

public string ItemTooltipText
{
Expand Down
61 changes: 61 additions & 0 deletions Files/Helpers/AsyncManualResetEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Files.Helpers
{
public class AsyncManualResetEvent
{
private volatile TaskCompletionSource<bool> m_tcs = new TaskCompletionSource<bool>();

public async Task WaitAsync(CancellationToken cancellationToken = default)
{
var tcs = m_tcs;
var cancelTcs = new TaskCompletionSource<bool>();

cancellationToken.Register(
s => ((TaskCompletionSource<bool>)s).TrySetCanceled(), cancelTcs);

await await Task.WhenAny(tcs.Task, cancelTcs.Task);
}

private async Task<bool> Delay(int milliseconds)
{
await Task.Delay(milliseconds);
return false;
}

public async Task<bool> WaitAsync(int milliseconds, CancellationToken cancellationToken = default)
{
var tcs = m_tcs;
var cancelTcs = new TaskCompletionSource<bool>();

cancellationToken.Register(
s => ((TaskCompletionSource<bool>)s).TrySetCanceled(), cancelTcs);

return await await Task.WhenAny(tcs.Task, cancelTcs.Task, Delay(milliseconds));
}

public void Set()
{
var tcs = m_tcs;
Task.Factory.StartNew(s => ((TaskCompletionSource<bool>)s).TrySetResult(true),
tcs, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default);
tcs.Task.Wait();
}

public void Reset()
{
while (true)
{
var tcs = m_tcs;
if (!tcs.Task.IsCompleted ||
Interlocked.CompareExchange(ref m_tcs, new TaskCompletionSource<bool>(), tcs) == tcs)
return;
}
}
}
}
30 changes: 10 additions & 20 deletions Files/Helpers/FileListCache/FileListCacheController.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Files.Common;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

Expand All @@ -14,40 +13,31 @@ public static FileListCacheController GetInstance()
return instance ??= new FileListCacheController();
}

private readonly IFileListCache persistentAdapter;

private FileListCacheController()
{
persistentAdapter = new PersistentSQLiteCacheAdapter();
}

private readonly Dictionary<string, object> fileNamesCache = new Dictionary<string, object>();
private readonly ConcurrentDictionary<string, string> fileNamesCache = new ConcurrentDictionary<string, string>();

public async Task<string> ReadFileDisplayNameFromCache(string path, CancellationToken cancellationToken)
public Task<string> ReadFileDisplayNameFromCache(string path, CancellationToken cancellationToken)
{
var displayName = fileNamesCache.Get(path, (string)null);
if (displayName == null)
if (fileNamesCache.TryGetValue(path, out var displayName))
{
displayName = await persistentAdapter.ReadFileDisplayNameFromCache(path, cancellationToken);
if (displayName != null)
{
fileNamesCache[path] = displayName;
}
return Task.FromResult(displayName);
}
return displayName;

return Task.FromResult<string>(null);
}

public Task SaveFileDisplayNameToCache(string path, string displayName)
{
if (displayName == null)
{
fileNamesCache.Remove(path);
return persistentAdapter.SaveFileDisplayNameToCache(path, displayName);
fileNamesCache.TryRemove(path, out _);
}
fileNamesCache[path] = displayName;

// save entry to persistent cache in background
return persistentAdapter.SaveFileDisplayNameToCache(path, displayName);
fileNamesCache[path] = displayName;
return Task.CompletedTask;
}
}
}
128 changes: 0 additions & 128 deletions Files/Helpers/FileListCache/PersistentSQLiteCacheAdapter.cs

This file was deleted.

Loading