Skip to content

Commit

Permalink
Improve performance of watcher, operations and props loading (#6028)
Browse files Browse the repository at this point in the history
  • Loading branch information
hez2010 authored Sep 6, 2021
1 parent 472cab3 commit 8c2d0b1
Show file tree
Hide file tree
Showing 11 changed files with 408 additions and 412 deletions.
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

0 comments on commit 8c2d0b1

Please sign in to comment.