Feature #13696
openAdd exchange and noreplace options to File.rename
Description
renameat2(2) introduced in linux kernel 3.15 takes following flags.
RENAME_EXCHANGE: Atomically exchange oldpath and newpath.
RENAME_NOREPLACE: Don't overwrite newpath of the rename. Return an error if newpath already exists.
This change makes File.rename
take these flags as keyword arguments.
Example:
File.write("hoge", "hoge")
File.write("fuga", "fuga")
File.rename("hoge", "fuga", exchange: true) # atomically exchanged
File.read("fuga") #=> "hoge"
File.rename("hoge", "fuga", noreplace: true) #=> File exists @ syserr_fail2_in - fuga (Errno::EEXIST)
Files
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
- Description updated (diff)
Glass_saga (Masaki Matsushita) wrote:
File.rename("hoge", "fuga", exchange: true) # atomically exchanged
How about another method, say, File.exchange
?
File.rename("hoge", "fuga", noreplace: true) #=> File exists @ syserr_fail2_in - fuga (Errno::EEXIST)
I prefer positive-form to negative-form as an option, i.e., File.rename(old, new[, replace: true])
.
Updated by shevegen (Robert A. Heiler) over 7 years ago
I prefer positive-form to negative-form as an option
I do too. I found it in general easier (for me) to understand positive/forward
declarations.
Updated by Glass_saga (Masaki Matsushita) over 7 years ago
- File patch.diff patch.diff added
Thank you for your comments.
I implemented FIle.exchange and made the noreplace flag in positive-form.
File.write("hoge", "hoge")
File.write("fuga", "fuga")
File.exchange("hoge", "fuga")
p File.read("fuga") #=> "hoge"
File.rename("hoge", "fuga", replace: false) #=> File exists @ syserr_fail2_in - fuga (Errno::EEXIST)
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
Is "atomically" important?
If no, it'd be possible to implement without kernel support.
Updated by normalperson (Eric Wong) over 7 years ago
nobu@ruby-lang.org wrote:
Is "atomically" important?
If no, it'd be possible to implement without kernel support.
Yes, atomicity is an important distinction.
We should not try to implement this non-atomically without kernel
support; it will quietly break code which expects the atomicity.
I am recalling similar problems around posix_fallocate in glibc:
https://sourceware.org/bugzilla/show_bug.cgi?id=15661
Updated by Glass_saga (Masaki Matsushita) over 7 years ago
I think atomicity is important. If the kernel doesn't support atomic exchange, File.exchange should raise NotImplementedError and users can handle it properly.
begin
File.exchange("hoge", "fuga")
rescue NotImplementedError
# exchange files in another way
end
Updated by duerst (Martin Dürst) about 7 years ago
nobu (Nobuyoshi Nakada) wrote:
Glass_saga (Masaki Matsushita) wrote:
File.rename("hoge", "fuga", exchange: true) # atomically exchanged
How about another method, say,
File.exchange
?File.rename("hoge", "fuga", noreplace: true) #=> File exists @ syserr_fail2_in - fuga (Errno::EEXIST)
I prefer positive-form to negative-form as an option, i.e.,
File.rename(old, new[, replace: true])
.
I think both exchange:
and noreplace:
are difficult to understand for an outside user. I think overwrite:
is much easier to understand.
Updated by shyouhei (Shyouhei Urabe) about 7 years ago
I think it's hard to have platform-specific API extensions like this to be in-core. If atomicity is such an important feature (and I'm sure it is), it's hard to emulate this in pure-userland for people without OS that support it.
This should be implemented as a gem. That way, gem install can bail out purposefully for unsupported platforms. That should prevent hidden race condition that you want to avoid.
Updated by hsbt (Hiroshi SHIBATA) 8 months ago
- Status changed from Open to Assigned