feat(fs-lock): new_try_exclusive and new_try_shared (#1496)

In certain situations it's useful to attempt to lock the file.
This commit is contained in:
Dawid Ciężarkiewicz 2023-11-16 14:35:08 -08:00 committed by GitHub
parent 9d8dc94d8d
commit 645579430a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -4,7 +4,7 @@
use std::{ use std::{
fs::File, fs::File,
io::{self, IoSlice, IoSliceMut, Result, SeekFrom}, io::{self, IoSlice, IoSliceMut, SeekFrom},
ops, ops,
}; };
@ -18,20 +18,54 @@ impl FileLock {
/// Take an exclusive lock on a [`File`]. /// Take an exclusive lock on a [`File`].
/// ///
/// Note that this operation is blocking, and should not be called in async contexts. /// Note that this operation is blocking, and should not be called in async contexts.
pub fn new_exclusive(file: File) -> Result<Self> { pub fn new_exclusive(file: File) -> io::Result<Self> {
file.lock_exclusive()?; file.lock_exclusive()?;
Ok(Self(file)) Ok(Self(file))
} }
/// Try to take an exclusive lock on a [`File`].
///
/// On success returns [`Self`]. On error the original [`File`] and optionally
/// an [`io::Error`] if the the failure was caused by anything other than
/// the lock being taken already.
///
/// Note that this operation is blocking, and should not be called in async contexts.
pub fn new_try_exclusive(file: File) -> Result<Self, (File, Option<io::Error>)> {
match file.try_lock_exclusive() {
Ok(()) => Ok(Self(file)),
Err(e) if e.raw_os_error() == fs4::lock_contended_error().raw_os_error() => {
Err((file, None))
}
Err(e) => Err((file, Some(e))),
}
}
/// Take a shared lock on a [`File`]. /// Take a shared lock on a [`File`].
/// ///
/// Note that this operation is blocking, and should not be called in async contexts. /// Note that this operation is blocking, and should not be called in async contexts.
pub fn new_shared(file: File) -> Result<Self> { pub fn new_shared(file: File) -> io::Result<Self> {
file.lock_shared()?; file.lock_shared()?;
Ok(Self(file)) Ok(Self(file))
} }
/// Try to take a shared lock on a [`File`].
///
/// On success returns [`Self`]. On error the original [`File`] and optionally
/// an [`io::Error`] if the the failure was caused by anything other than
/// the lock being taken already.
///
/// Note that this operation is blocking, and should not be called in async contexts.
pub fn new_try_shared(file: File) -> Result<Self, (File, Option<io::Error>)> {
match file.try_lock_shared() {
Ok(()) => Ok(Self(file)),
Err(e) if e.raw_os_error() == fs4::lock_contended_error().raw_os_error() => {
Err((file, None))
}
Err(e) => Err((file, Some(e))),
}
}
} }
impl Drop for FileLock { impl Drop for FileLock {
@ -54,37 +88,37 @@ impl ops::DerefMut for FileLock {
} }
impl io::Write for FileLock { impl io::Write for FileLock {
fn write(&mut self, buf: &[u8]) -> Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf) self.0.write(buf)
} }
fn flush(&mut self) -> Result<()> { fn flush(&mut self) -> io::Result<()> {
self.0.flush() self.0.flush()
} }
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> { fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs) self.0.write_vectored(bufs)
} }
} }
impl io::Read for FileLock { impl io::Read for FileLock {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf) self.0.read(buf)
} }
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> { fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs) self.0.read_vectored(bufs)
} }
} }
impl io::Seek for FileLock { impl io::Seek for FileLock {
fn seek(&mut self, pos: SeekFrom) -> Result<u64> { fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
self.0.seek(pos) self.0.seek(pos)
} }
fn rewind(&mut self) -> Result<()> { fn rewind(&mut self) -> io::Result<()> {
self.0.rewind() self.0.rewind()
} }
fn stream_position(&mut self) -> Result<u64> { fn stream_position(&mut self) -> io::Result<u64> {
self.0.stream_position() self.0.stream_position()
} }
} }