-
Notifications
You must be signed in to change notification settings - Fork 82
Reduce allocations in PhysicalFileProvider when GetDirectoryContents is called but not enumerated #240
Conversation
Typo. This resolves #224 not 214 |
@@ -13,6 +13,11 @@ namespace Microsoft.Extensions.FileProviders | |||
public class NotFoundDirectoryContents : IDirectoryContents | |||
{ | |||
/// <summary> | |||
/// A shared instance of <see cref="NotFoundDirectoryContents"/> | |||
/// </summary> | |||
public static NotFoundDirectoryContents Singleton { get; } = new NotFoundDirectoryContents(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've use Singleton
in abstractions, e.g. NullChangeToken.Singleton. Seems like they mean the same thing. Is there some nuance I'm missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha. Never mind in that case.
|
||
private static IDirectoryContents GetEnumerableContents(string fullPath) | ||
{ | ||
return new EnumerableDirectoryContents(() => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't we pass in the DirectoryInfo
to EnumerableDirectoryContents
and have it iterate it lazily (instead of passing in the Func?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could, but EnumerableDirectoryContents shared with providers that don't necessarily use the physical file system.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we fork it and make a PhysicalDirectoryContents
? There's not much to implement in the interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered that too and started an implementation with that approach, but ended up with the current implementation. There are probably a dozen ways it could be done, but I landed on this. I couldn't see a strong case for adding a new type such as PhysicalDirectoryContents
.
|
||
private void EnsureInitialized() | ||
{ | ||
LazyInitializer.EnsureInitialized(ref _entries, _entriesFactory); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably don't need any of the behavior of LazyInitializer
. if (_entries == null) { .. }` should suffice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. Will update.
Ping. @Tratcher can you also review? |
}); | ||
|
||
return new EnumerableDirectoryContents(contents); | ||
return GetEnumerableContents(fullPath); | ||
} | ||
catch (DirectoryNotFoundException) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do these catches need to be moved within the closure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good catch. Due to our lazy instantiation of the enumerator, it's possible the directory could be deleted after we create the EnumerableDirectoryContents and before it's enumerated. I'll move it inside the closure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or duplicate it..
87aa57f
to
35779b9
Compare
🆙 📅 |
28754ae
to
a54ef9c
Compare
Resolves #224
Optimize PhysicalFileProvider for scenario when it is basically being used for Directory.Exists() (cough, looking at you, aspnet/StaticFiles).
Add singleton of NotFoundDirectoryContents.
Delay calling DirectoryInfo.EnumerateFileSystemInfos which does lots of up-front allocation.
Benchmark: 100 checks for directory that exists but contents not enumerated
Importantly, this isn't creating an enumerator. We just want to know if the directory exist.
Before:
After:
Benchmark: 100 checks for directory that does not exists
Before:
After:
cc @davidfowl @Tratcher