FFMG / myoddweb.directorywatcher

A fast and reliable, (non blocking!), .NET/C++ File/Directory watcher, complete rewrite of FileSystemWatcher to ensure speed/accuracy/reliability/suppress duplicate events.
MIT License
50 stars 12 forks source link

Freezing at Stop(); #2

Closed milos12345 closed 4 years ago

milos12345 commented 5 years ago

I'm working on a file manager using this directorywatcher. Every time user navigates to a new folder I am resetting the monitored folder with:

watcher.Stop();
watcher.Add(new Request(currentPath, false));
watcher.Start();

Is this a proper way to use it? I have concerns because on a few occasions for program froze, and if I press Pause in VS the debugger would point to the line with Stop(). So far I have not been to consistently reproduce the issue as it may happen once in an hour in random folders, so I am just trying to rule out that I am using incorrectly?

FFMG commented 5 years ago

Hi,

It shouldn't cause any issues calling 'Stop()', let me write a small app and try a few times to see if I can get it to happen.

Thanks

FFMG commented 5 years ago

Hi, I cannot reproduce this issue, are you able to share the code?

Also, from you comment is looks like you are calling "Stop()" from within the callback function, is that correct or are you doing it some other way?

Are you able to share a small code sample of what you are doing.

milos12345 commented 5 years ago

It is not in callback function but in something like this

private void FileBrowser_Click(object sender, MouseButtonEventArgs e)
{
    watcher.Stop();
    var itemClicked = ItemsControl.ContainerFromElement((ListBox)sender, e.OriginalSource as DependencyObject) as ListBoxItem;
    DirectoryInfo dirInfo = (DirectoryInfo)itemClicked.Content;
    System.IO.FileInfo[] f = dirInfo.GetFiles();  
    for (int i = 0; i <= f.Length; i++)
    {
        Output(f);
    }
    watcher.Add(new Request(dirInfo.FullName, false));
    watcher.Start();
}

So every folder click in listbox it will stop watcher and resume after files are listed; but give me a few days to just check if I solved it. I have not had freezing in a few days, and since then I rewrote a part of my program, maybe back then I had one of those calls in a non-UI thread, but I also added a buffer for collecting changes from watcher, and just flush it to once a second. Let me just verify if it happens again, as even then I was once in half an hour of use so it is really hard to catch

FFMG commented 5 years ago

Hi,

Just to confirm, when you call:

watcher.Stop();
...
watcher.Add( ... );
...
watcher.Start();

You are not removing the previous folders being watched , you are just adding more and more folder.

If that's what you want, then you can just add folders, no need to Stop/Start.

watcher.Add( ... );
...

If you want to watch other folders, you are better off doing

watcher.Stop();
watcher = new Watcher( ... )
...
watcher.Add( ... );
...
watcher.Start();

In any case, I identified an issue, and I made some changes to prevent 'freezing' further and will release in the next few days'

It is currently in a feature branch.

Thanks

milos12345 commented 5 years ago

Thank you! I was going for the second situation to have only one watched folder at a time. Do I need to call Stop() or will it automatically dispose all when new Wacher is created. I ask because calling Stop() takes about 250ms so when a folder changes, it will freeze the UI enough to make browsing and animations lag, so I was trying to prevent that. When ready, please also update the nuget package.

FFMG commented 5 years ago

Ok, I updated the nuget packages, give it some time to propagate and it should all be good.

Give me a shout if you have any issues.

I will keep this open for a little while longer.

milos12345 commented 4 years ago

Don't close is just yet, just updating the nuget broke several parts of the program, like listbox is completely frozen where directorywatcher is On. I also have a toggle to switch between FileSystemWatcher and directorywatcher, and issue is only when it directorywatcher is On. I'll try to find the issue...

FFMG commented 4 years ago

Is your app open source? Or can you create a small sample app that would reproduce the issue?

Otherwise there a sample section in my source code, maybe it can help?

Not that it really matters, but I added support for .NET 4..6.2, .NET Core 3.0 and .NET Standard 2.0, it might make it easier to trace what the issue might be.

milos12345 commented 4 years ago

Updated Nuget. Now on watcher.Start() there is an error:

Unable to load the interop file. 'file:///D:\proj\proj\bin\x64\myoddweb.directorywatcher.interop.x64.dll'.

The D:\proj\proj\bin has release and debug folders, and neither has that dll, just

myoddweb.directorywatcher.dll
myoddweb.directorywatcher.interfaces.dll

EDIT: It is not open source, and is may be too convoluted at the moment for ones who did not spend 5 years on it. Version is 0.1.5. I assume nuget should place dlls in correct folders on compile

FFMG commented 4 years ago

Hum, very strange.

I am using the sample solution and I do a clean build and it all works as expected.

I have tried x64, x86 and so on, with version 0.1.5

Yes, nuget places all the files in the package directory.

milos12345 commented 4 years ago

I am using VS2017 and target .NET 4.6.2, and trying it in debug build for AnyCPU. I don't see that myoddweb.directorywatcher.interop.x64.dll. Both Debug and Release have myoddweb.directorywatcher.dll myoddweb.directorywatcher.interfaces.dll

FFMG commented 4 years ago

The interop file is embedded, (it is the second project in the repo)

I will try and investigate why this file cannot be located ... given that it is embedded inside the code.

FFMG commented 4 years ago

Aslo, you have not answered my other question, have you tried the sample application? Does it work for you?

milos12345 commented 4 years ago

I have just tried sample application in VS2017 opening sln from samples. It could not resolve references, so I removed nuget packages, and added 0.1.5 again and it throws the same error

milos12345 commented 4 years ago

Tried VS2019 and is the same On first run get this: image I have only .NET 4.6.1 as target as some program users still use that version. Not sure if that is makes a difference. Getting nuget again runs the app but throws at the same place

From console

Press Ctrl+C to stop the monitors.
System.IO.FileNotFoundException: Could not load file or assembly 'file:///D:\temp\myoddweb.directorywatcher-master\samples\bin\x64\myoddweb.directorywatcher.interop.x64.dll' or one of its dependencies. The system cannot find the file specified.
File name: 'file:///D:\temp\myoddweb.directorywatcher-master\samples\bin\x64\myoddweb.directorywatcher.interop.x64.dll'
   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boolean forIntrospection, Boolean suppressSecurityChecks, StackCrawlMark& stackMark)
   at System.Reflection.Assembly.LoadFrom(String assemblyFile)
   at myoddweb.directorywatcher.utils.TypeLoader.LoadTypeFromAssembly[T](String assemblyFilePath)
   at myoddweb.directorywatcher.utils.WatcherManager.CreateWatcherFromFileSystem()

=== Pre-bind state information ===
LOG: Where-ref bind. Location = D:\temp\myoddweb.directorywatcher-master\samples\bin\x64\myoddweb.directorywatcher.interop.x64.dll
LOG: Appbase = file:///D:/temp/myoddweb.directorywatcher-master/samples/bin/Debug/
LOG: Initial PrivatePath = NULL
Calling assembly : (Unknown).
===
LOG: This bind starts in LoadFrom load context.
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load().
LOG: Using application configuration file: D:\temp\myoddweb.directorywatcher-master\samples\bin\Debug\myoddweb.directorywatcher.sample.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Attempting download of new URL file:///D:/temp/myoddweb.directorywatcher-master/samples/bin/x64/myoddweb.directorywatcher.interop.x64.dll.

Unable to load the interop file. 'file:///D:\temp\myoddweb.directorywatcher-master\samples\bin\x64\myoddweb.directorywatcher.interop.x64.dll'.

Could not load file or assembly 'file:///D:\temp\myoddweb.directorywatcher-master\samples\bin\x64\myoddweb.directorywatcher.interop.x64.dll' or one of its dependencies. The system cannot find the file specified.
FFMG commented 4 years ago

I have to admit, I am a little baffled here.

First of all, the reason why you got the error is because it was targetting .NET 4.8 so you had to update the package update-package myoddweb.directorywatcher -reinistall, (as you noticed yourself)

In any case, I made some changes to a new branch to log more errors to try and give a bit more of a clue.

Can I please ask you to check out a temp branch... feature/resolve

Then there is a solution D:\temp\myoddweb.directorywatcher-master/samples/myoddweb.directorywatcher.ref.sln, (almost the same as the one you were running earlier). That version tagets 4.5.2

That solution should give more details as to what is going on. If that works, could you please change the target to 4.6.1 and try again.

Can you please run it and copy the output here please.

Thanks a lot.

milos12345 commented 4 years ago

Once I opened myoddweb.directorywatcher.ref.sln from feature/resolve the VS prompted me to install something related to C++ but I accepted it without reading and the the sample app ran without issues in VS2017 and 2019. Even the one from yesterday ran. Changing target to 4.6.1. also works. I'm not sure what it is, but something that was not there in 0.1.3 (last version that worked without that C++ component). I'll try tomorrow on work PC to see what made the difference.

FFMG commented 4 years ago

Ah ... maybe it is the VC++ dependencies, let me try and uninstall mine to see ...

milos12345 commented 4 years ago

I tried it on another PC, installed Desktop development with C++ workload, but it still would not work in VS2017 complaining about "The build tools for v142... cannot be found". I have also tried opening my project that originally failed to upgrade from 0.1.3 to 0.1.5 in VS2017 and it was throwing that System.IO.FileNotFoundException... myoddweb.directorywatcher.interop.x64.dll exception.

But then I Installed VS2019 with Desktop development with C++ workload. I tried again opening my project with directorywatcher 0.1.5 in VS2017 and now it does not throw exception and so far it seems that it runs without issues.

So it does need VS2019 or those that build tools for v142 which is not available in VS2017. I'm not sure why 2017 would work, but I'm glad it does. I will continue working on my project tomorrow and see if there are any new issues.

FFMG commented 4 years ago

Ok, thanks for all the help, I know what the issue is now, (it requires the 2019 C++ dependencies).

I am busy fixing it so that is not required anymore ... I will post an update here once I am done.

Edit: I was wrong that is not the issue.

FFMG commented 4 years ago

Ok, I tried on ....

I did not install C++ at all, all I installed was .NET 4.6, (the default install). I created a very simple project, and it all worked just fine... no issue at all.

I will try and play around again to try and reproduce it.

milos12345 commented 4 years ago

Thanks for looking into this! On this clean install, did you just install directorywatcher through nuget as that is what was not working on the versions I had. Right now I am on work PC where I had 0.1.3 upgraded to 0.1.5. I have not installed VS2019 here so I can test that it is working once you update nuget.

FFMG commented 4 years ago

Ok, I was finally able to reproduce it on a clean install of Windows 10 + VS2017, for some reason I cannot get it to happen on a clean install of VS2019

Can you please try update-package MyOddWeb.DirectoryWatcher -Version 0.1.6-alpha1 update-package MyOddWeb.DirectoryWatcher -Version 0.1.6-alpha2, because the version is in Alpha you need to include the version number rather than just update.

I am still running some edge case tests here, but if you could also try it that would be great.

If you do not use the package console make sure to select pre-release image

And select version 0.1.6-alpha1 0.1.6-alpha2

Edit: I already found a small issue while running my tests ... but it would still be interesting to see if that works for you. Will do a proper release later today.

Edit 2: Ok, I think I fixed all the issues, if you could try alpha2 that would be great, thanks.

Thanks

FFMG commented 4 years ago

Ok, I made more changes and I think it is good to go for now.

update-package MyOddWeb.DirectoryWatcher -Version 0.1.6-alpha2

Thanks

milos12345 commented 4 years ago

Great! Just updating the package in my VS2017 project through console fixed the issue on that computer without the VS2019 installed. I will be using it in the next days and will get back to you if I see any bugs. Thank you for fixing this!

FFMG commented 4 years ago

Glad to hear, I still have a little bit of cleanup to do and I will then release a non-alpha version of 0.1.6

Let me know if you come across anything else.

Thanks

FFMG commented 4 years ago

Ok, I released version 0.1.6 and it seems to cover the various issues picked-up in this conversation.

Just start a new issue if you come across anything.

Thanks