WindowsFile: Retrieve correct Win32 error codes#3337
Conversation
780f3b3 to
145be17
Compare
WindowsFile calls GetLastError via win32-api to retrieve win32 error code but the error code may be already reset by Ruby's internal code so that it can't retrive a correct error code. Sometimes it causes random unrecoverable errors when in_tail plugin tries to read a non-existent file like the following: 2021-04-14 03:15:45 +0000 [error]: #2 Fluent::Win32Error code: 158, The segment is already unlocked.: C:/path/to/log.txt Fiddle or FFI has a method to avoid this issue: * Fiddle.win32_last_error https://ruby-doc.org/stdlib-3.0.0/libdoc/fiddle/rdoc/Fiddle.html#method-c-win32_last_error * FFI::LastError.winapi_error https://www.rubydoc.info/github/ffi/ffi/FFI/LastError#winapi_error-instance_method We've added an equivalent method for win32-api: cosmo0920/win32-api#55 This commit replaces the retrieving the error code with this method. Signed-off-by: Takuro Ashie <ashie@clear-code.com>
145be17 to
a51ee09
Compare
cosmo0920
left a comment
There was a problem hiding this comment.
I'd confirmed that this patch can fix WindowsFile exceptions testing failures on Ruby 3.0 at current master(8c7d674).
At master(8c7d674):
WindowsFile exceptions:
test: ERROR_SHARING_VIOLATION raised: F
========================================================================================================================
Failure: test: ERROR_SHARING_VIOLATION raised(FileWrapperTest::WindowsFile exceptions)
./test/plugin/test_file_wrapper.rb:95:in `block (2 levels) in <class:FileWrapperTest>'
92: path = "#{TMP_DIR}/test_windows_file.txt"
93: file1 = file2 = nil
94: file1 = File.open(path, "wb")
=> 95: assert_raise(Fluent::Win32Error.new(ERROR_SHARING_VIOLATION, path)) do
96: file2 = Fluent::WindowsFile.new(path, 'r', FILE_SHARE_READ)
97: ensure
98: file2.close if file2
<#<Fluent::Win32Error: code: 32, The process cannot access the file because it is being used by another process. - ./test/plugin/../tmp/file_wrapper/test_windows_file.txt>> expected but was
<#<Fluent::Win32Error: code: 0, The operation completed successfully. - ./test/plugin/../tmp/file_wrapper/test_windows_file.txt>>
diff:
? #<Fluent::Win32Error: code: 32, The p r o c e ss cannot access the file because it is being used by another process. - ./test/plugin/../tmp/file_wrapper/test_windows_file.txt>
? 0 o e ati n ompl ted u u l
========================================================================================================================
: (0.029622)
test: Errno::ENOENT raised: F
========================================================================================================================
Failure: test: Errno::ENOENT raised(FileWrapperTest::WindowsFile exceptions)
./test/plugin/test_file_wrapper.rb:83:in `block (2 levels) in <class:FileWrapperTest>'
80: test 'Errno::ENOENT raised' do
81: path = "#{TMP_DIR}/nofile.txt"
82: file = nil
=> 83: assert_raise(Errno::ENOENT) do
84: file = Fluent::WindowsFile.new(path)
85: ensure
86: file.close if file
<Errno::ENOENT> expected but was
<#<Fluent::Win32Error: code: 0, The operation completed successfully. - ./test/plugin/../tmp/file_wrapper/nofile.txt>>
diff:
? Err no::ENOENT
? #<Fluent::Win32 or: code: 0, The operation completed successfully. - ./test/plugin/../tmp/file_wrapper/ file.txt>
========================================================================================================================
: (0.009904)
test: nothing raised: .: (0.002036)
With this patch:
WindowsFile exceptions:
test: ERROR_SHARING_VIOLATION raised: .: (0.001875)
test: Errno::ENOENT raised: .: (0.000978)
test: nothing raised:
|
Other testing failures are caused by weird WSAGetLastError return codes. |
|
@ashie I have a vague uncomfortableness with this Should not we assign some value to this variable? I felt that the variable was |
Thank you for pointing out it. |
fujimotos
left a comment
There was a problem hiding this comment.
Aside from the point above, I'm comfortable with this patch.
Which issue(s) this PR fixes:
none
What this PR does / why we need it:
WindowsFile calls GetLastError via win32-api to retrieve win32 error
code but the error code may be already reset by Ruby's internal code
so that it can't retrive a correct error code. Sometimes it causes
random unrecoverable errors when in_tail plugin tries to read a
non-existent file like the following:
Fiddle or FFI has a method to avoid this issue:
https://ruby-doc.org/stdlib-3.0.0/libdoc/fiddle/rdoc/Fiddle.html#method-c-win32_last_error
https://www.rubydoc.info/github/ffi/ffi/FFI/LastError#winapi_error-instance_method
We've added an equivalent method for win32-api:
This commit replaces the retrieving the error code with this method.
Docs Changes:
none
Release Note:
Same with the title.