[Common]Use folder_change_reader in file watcher to improve performance (#30827)

This commit is contained in:
Davide Giacometti
2024-01-12 16:23:00 +01:00
committed by GitHub
parent 4ce38d192d
commit 4f06f2a659
7 changed files with 52 additions and 45 deletions

View File

@@ -1,5 +1,6 @@
#include "pch.h" #include "pch.h"
#include "FileWatcher.h" #include "FileWatcher.h"
#include <utils/winapi_error.h>
std::optional<FILETIME> FileWatcher::MyFileTime() std::optional<FILETIME> FileWatcher::MyFileTime()
{ {
@@ -19,50 +20,47 @@ std::optional<FILETIME> FileWatcher::MyFileTime()
return result; return result;
} }
void FileWatcher::Run() FileWatcher::FileWatcher(const std::wstring& path, std::function<void()> callback) :
{
while (1)
{
auto lastWrite = MyFileTime();
if (!m_lastWrite.has_value())
{
m_lastWrite = lastWrite;
}
else if (lastWrite.has_value())
{
if (m_lastWrite->dwHighDateTime != lastWrite->dwHighDateTime ||
m_lastWrite->dwLowDateTime != lastWrite->dwLowDateTime)
{
m_lastWrite = lastWrite;
m_callback();
}
}
if (WaitForSingleObject(m_abortEvent, m_refreshPeriod) == WAIT_OBJECT_0)
{
return;
}
}
}
FileWatcher::FileWatcher(const std::wstring& path, std::function<void()> callback, DWORD refreshPeriod) :
m_refreshPeriod(refreshPeriod),
m_path(path), m_path(path),
m_callback(callback) m_callback(callback)
{ {
m_abortEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr); std::filesystem::path fsPath(path);
if (m_abortEvent) m_file_name = fsPath.filename();
std::transform(m_file_name.begin(), m_file_name.end(), m_file_name.begin(), ::towlower);
m_folder_change_reader = wil::make_folder_change_reader_nothrow(
fsPath.parent_path().c_str(),
false,
wil::FolderChangeEvents::LastWriteTime,
[this](wil::FolderChangeEvent, PCWSTR fileName) {
std::wstring lowerFileName(fileName);
std::transform(lowerFileName.begin(), lowerFileName.end(), lowerFileName.begin(), ::towlower);
if (m_file_name.compare(fileName) == 0)
{
auto lastWrite = MyFileTime();
if (!m_lastWrite.has_value())
{
m_lastWrite = lastWrite;
}
else if (lastWrite.has_value())
{
if (m_lastWrite->dwHighDateTime != lastWrite->dwHighDateTime ||
m_lastWrite->dwLowDateTime != lastWrite->dwLowDateTime)
{
m_lastWrite = lastWrite;
m_callback();
}
}
}
});
if (!m_folder_change_reader)
{ {
m_thread = std::thread([this]() { Run(); }); Logger::error(L"Failed to start folder change reader for path {}. {}", path, get_last_error_or_default(GetLastError()));
} }
} }
FileWatcher::~FileWatcher() FileWatcher::~FileWatcher()
{ {
if (m_abortEvent) m_folder_change_reader.reset();
{
SetEvent(m_abortEvent);
m_thread.join();
CloseHandle(m_abortEvent);
}
} }

View File

@@ -11,16 +11,14 @@
class FileWatcher class FileWatcher
{ {
DWORD m_refreshPeriod;
std::wstring m_path; std::wstring m_path;
std::wstring m_file_name;
std::optional<FILETIME> m_lastWrite; std::optional<FILETIME> m_lastWrite;
std::function<void()> m_callback; std::function<void()> m_callback;
HANDLE m_abortEvent; wil::unique_folder_change_reader_nothrow m_folder_change_reader;
std::thread m_thread;
std::optional<FILETIME> MyFileTime(); std::optional<FILETIME> MyFileTime();
void Run();
public: public:
FileWatcher(const std::wstring& path, std::function<void()> callback, DWORD refreshPeriod = 1000); FileWatcher(const std::wstring& path, std::function<void()> callback);
~FileWatcher(); ~FileWatcher();
}; };

View File

@@ -47,10 +47,15 @@
<ProjectReference Include="..\..\common\version\version.vcxproj"> <ProjectReference Include="..\..\common\version\version.vcxproj">
<Project>{cc6e41ac-8174-4e8a-8d22-85dd7f4851df}</Project> <Project>{cc6e41ac-8174-4e8a-8d22-85dd7f4851df}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="..\..\..\deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" /> <Import Project="..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup> </ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <PropertyGroup>
@@ -58,5 +63,6 @@
</PropertyGroup> </PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props'))" /> <Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets'))" /> <Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target> </Target>
</Project> </Project>

View File

@@ -9,3 +9,5 @@
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <common/logger/logger.h>
#include <wil/filesystem.h>

View File

@@ -3,6 +3,7 @@
#include <windows.h> #include <windows.h>
#include <winrt/base.h> #include <winrt/base.h>
#include <wil/resource.h> #include <wil/resource.h>
#include <wil/filesystem.h>
#include <ProjectTelemetry.h> #include <ProjectTelemetry.h>
#include <common/logger/logger.h> #include <common/logger/logger.h>

View File

@@ -13,8 +13,9 @@
#include <ShellScalingApi.h> #include <ShellScalingApi.h>
#include <strsafe.h> #include <strsafe.h>
#include <TraceLoggingActivity.h> #include <TraceLoggingActivity.h>
#include <wil\resource.h> #include <wil/filesystem.h>
#include <wil\result.h> #include <wil/resource.h>
#include <wil/result.h>
#include <winrt/windows.foundation.h> #include <winrt/windows.foundation.h>
#include <psapi.h> #include <psapi.h>
#include <shared_mutex> #include <shared_mutex>

View File

@@ -9,6 +9,7 @@
#include <wil/resource.h> #include <wil/resource.h>
#include <wil/com.h> #include <wil/com.h>
#include <wil/filesystem.h>
#include <string_view> #include <string_view>
#include <optional> #include <optional>