Open sunfishcode opened 2 years ago
I found a solution that works with this specific example:
fn main() -> std::io::Result<()> {
let mut lock = RwLock::new(File::open("test")?);
// store in a variable so we can later explicitly drop it during the match
let try_result = lock.try_write();
let mut guard = match try_result {
Ok(guard) => guard,
// only borrow the error here via `ref`, instead of moving it out since that would
// prevent the explicit early drop of `try_result`
Err(ref err) if err.kind() == std::io::ErrorKind::WouldBlock => {
drop(try_result);
eprintln!("blocking on other processes...");
lock.write()?
}
Err(err) => return Err(err),
};
let _use = &mut guard;
Ok(())
}
However, if you need to return the guard from a function, it will trigger an instance of https://docs.rs/polonius-the-crab/0.3.1/polonius_the_crab/#rationale-limitations-of-the-nll-borrow-checker. Eventually the polonius
borrow checker should allow cases like this to work IIUC.
Alternatively, would it makes sense for
try_write
andwrite
to take a&self
instead of a&mut self
? They don't need the mut for any of their own state.
As I noted in https://github.com/yoshuawuyts/fd-lock/pull/30#issuecomment-1387523367, system APIs can allow conflicting lock calls to succeed if the same file handle is used. Potentially, additional synchronization could be added internally in fd-lock
to allow this to take &self
and keep the same functionality (this could be used to also support Arc
based guard types). Alternatively, APIs to specifically support this try_write
then write
case could be introduced.
Wow, thanks for that @Imberflur. I didn't think of that, but it works and compiles now. Previously, I cloned File
and created a new RwLock
in the Err
arm, which wasn't pretty or elegant at all. Oh, but I had to add ref
to Err(ref err) if err.kind() == ErrorKind::WouldBlock => {
even though I don't use err
inside the code block. :/
I have 2 small questions that are just for this use case (addressed to anyone that knows). The docs only use File::open()
so here is what I wanna know:
let file = match OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(lock_file_path.as_path())
since I want to delete the file after its usage.
remove_file()
before the drop
is called?So far I tried both and it looks like it works just fine.
This program does a
try_write()
, and if that fails due to another process holding the lock, prints a message, and then does awrite()
to wait until the lock is available:However, this doesn't compile:
Is there a way to do what this code is doing that avoids this problem?
Alternatively, would it makes sense for
try_write
andwrite
to take a&self
instead of a&mut self
? They don't need themut
for any of their own state.