8000 Use FILE_SHARE_DELETE for log files on Windows. by cpuguy83 · Pull Request #39974 · moby/moby · GitHub
[go: up one dir, main page]

Skip to content

Conversation

cpuguy83
Copy link
Member
@cpuguy83 cpuguy83 commented Sep 23, 2019

This (hopefully! 🤞 ) fixes issues where one goroutine tries to delete or rename a file
while another goroutine has the file open (e.g. a log reader).

Closes #39856
Closes #36801
Fixes #39274

@thaJeztah
Copy link
Member

@ddebroy @olljanat @vikramhh PTAL

@olljanat
Copy link
Contributor
olljanat commented Sep 23, 2019

To be honest I don't understand how this would work even on theory?

Sharemode is hardcoded on https://github.com/golang/go/blob/4219aec60ab473fa00f1092034ca801218a5dbe9/src/syscall/syscall_windows.go#L297 and that why there is that very long discussion about changing that hardcoded flag on golang/go#32088

Btw. You can use my unit test for this one https://github.com/olljanat/go/commit/3828f1a5d0ebb69b4c459d5243799ded36ac1ee8 if that passes on Windows you are good to go.

@cpuguy83 cpuguy83 force-pushed the fix_windows_file_handles branch from b749478 to b65a8b6 Compare September 23, 2019 23:40
@cpuguy83
Copy link
Member Author

@olljanat You're right.
So now I've copied syscall.Open with just the one modification for FILE_SHARE_DELETE.
Added a unit test for the functionality.

I had to pull in a few other functions from os to mimic os.OpenFile just in case there is some edge case... probably not even important.

This fixes issues where one goroutine tries to delete or rename a file
while another goroutine has the file open (e.g. a log reader).

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
@cpuguy83 cpuguy83 force-pushed the fix_windows_file_handles branch from b65a8b6 to a5f237c Compare September 23, 2019 23:45
"github.com/pkg/errors"
)

func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we move this to pkg/system? In that package we also have some other windows-specific utilities (some of which) can be used as drop-in replacements for their default go implementations, e.g.

// MkdirAll implementation that is volume path aware for Windows. It can be used
// as a drop-in replacement for os.MkdirAll()
func MkdirAll(path string, _ os.FileMode) error {
return mkdirall(path, false, "")
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm intending this as a targeted workaround for a very specific and real issue rather than a generic solution.

It would be nice if go picked up some change to support this option.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm intending this as a targeted workaround for a very specific and real issue rather than a generic solution.

Gotcha. I was thinking if other places would also benefit from this, having it in that package would make it a slightly bit more reusable; not a blocker though

It would be nice if go picked up some change to support this option

Yes, definitely

@olljanat
Copy link
Contributor

@cpuguy83 Now it it looks likely that it will use FILE_SHARE_DELETE share mode but note that it actually only solves a part of the problem. If you remove file which is created with that flag and try open new one without closing original open handle it will still fail.

Only way to prevent that is rename file for some name which is not used by any other process before removing it. So if I understand this right it should be added to just before os.Remove to:

lastFile := fmt.Sprintf("%s.%d%s", name, maxFiles-1, extension)
err := os.Remove(lastFile)
if err != nil && !os.IsNotExist(err) {
return errors.Wrap(err, "error removing oldest log file")
}

@cpuguy83
Copy link
Member Author
cpuguy83 commented Sep 24, 2019

@olljanat Do you have some example code to reproduce this?
The simple one I came up with (call openFile again after the file is removed in the test I added TestOpenFileDelete ) does not repro that case.

@olljanat
Copy link
Contributor

@cpuguy83 Hmm. It was mentioned on golang/go#32088 (comment) that defaults have been changed on latest versions of Windows and it really looks to be case at least on Windows 10, version 1903 so this simple PowerShell script works just fine on it but fails example on Windows Server 2019:

$file = [System.IO.File]::Open("c:\temp\test.txt", "Create", "ReadWrite", "Delete")
Remove-Item -Path c:\temp\test.txt
$file2 = [System.IO.File]::Open("c:\temp\test.txt", "Create", "ReadWrite", "Delete")

@ddebroy
Copy link
Contributor
ddebroy commented Sep 24, 2019

/cc @ameyag

Copy link
Member
@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@thaJeztah thaJeztah merged commit 37760f0 into moby:master Oct 3, 2019
@andrewhsu
Copy link
Contributor

I'll see if this helps with master builds that fail on RS1 https://ci.docker.com/public/blue/organizations/jenkins/moby/activity/?branch=master

@thaJeztah
Copy link
Member

We can cherry-pick once we see master is more stable with this 👍

@cpuguy83 cpuguy83 deleted the fix_windows_file_handles branch October 7, 2019 17:23
olljanat added a commit to olljanat/moby that referenced this pull request Oct 22, 2019
…ows versions

Signed-off-by: Olli Janatuinen <olli.janatuinen@gmail.com>
@thaJeztah thaJeztah added this to the 20.03.0 milestone Feb 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Flaky test: Integration test failure on Windows: TestJSONFileLoggerWithOpts Docker json-file logging driver hangs when rotating files on Windows
6 participants
0