Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 42b9823

Browse filesBrowse files
committed
Optimize Seek::stream_len impl for File
It uses the file metadata on Unix with a fallback for files incorrectly reported as zero-sized. It uses `GetFileSizeEx` on Windows. This reduces the number of syscalls needed for determining the file size of an open file from 3 to 1.
1 parent 6be7b0c commit 42b9823
Copy full SHA for 42b9823

File tree

10 files changed

+84
-10
lines changed
Filter options

10 files changed

+84
-10
lines changed

‎library/std/src/fs.rs

Copy file name to clipboardExpand all lines: library/std/src/fs.rs
+32Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,9 +823,38 @@ impl Write for &File {
823823
}
824824
#[stable(feature = "rust1", since = "1.0.0")]
825825
impl Seek for &File {
826+
/// Seek to an offset, in bytes in a file.
827+
///
828+
/// See [`Seek::seek`] docs for more info.
829+
///
830+
/// # Platform-specific behavior
831+
///
832+
/// This function currently corresponds to the `lseek64` function on Unix
833+
/// and the `SetFilePointerEx` function on Windows. Note that this [may
834+
/// change in the future][changes].
835+
///
836+
/// [changes]: io#platform-specific-behavior
826837
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
827838
self.inner.seek(pos)
828839
}
840+
841+
/// Returns the length of this file (in bytes).
842+
///
843+
/// See [`Seek::stream_len`] docs for more info.
844+
///
845+
/// # Platform-specific behavior
846+
///
847+
/// This function currently corresponds to the `statx` function on Linux
848+
/// (with fallbacks) and the `GetFileSizeEx` function on Windows. Note that
849+
/// this [may change in the future][changes].
850+
///
851+
/// [changes]: io#platform-specific-behavior
852+
fn stream_len(&mut self) -> io::Result<u64> {
853+
if let Some(result) = self.inner.size() {
854+
return result;
855+
}
856+
io::stream_len_default(self)
857+
}
829858
}
830859

831860
#[stable(feature = "rust1", since = "1.0.0")]
@@ -872,6 +901,9 @@ impl Seek for File {
872901
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
873902
(&*self).seek(pos)
874903
}
904+
fn stream_len(&mut self) -> io::Result<u64> {
905+
(&*self).stream_len()
906+
}
875907
}
876908

877909
#[stable(feature = "io_traits_arc", since = "1.73.0")]

‎library/std/src/io/mod.rs

Copy file name to clipboardExpand all lines: library/std/src/io/mod.rs
+16-10Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1995,16 +1995,7 @@ pub trait Seek {
19951995
/// ```
19961996
#[unstable(feature = "seek_stream_len", issue = "59359")]
19971997
fn stream_len(&mut self) -> Result<u64> {
1998-
let old_pos = self.stream_position()?;
1999-
let len = self.seek(SeekFrom::End(0))?;
2000-
2001-
// Avoid seeking a third time when we were already at the end of the
2002-
// stream. The branch is usually way cheaper than a seek operation.
2003-
if old_pos != len {
2004-
self.seek(SeekFrom::Start(old_pos))?;
2005-
}
2006-
2007-
Ok(len)
1998+
stream_len_default(self)
20081999
}
20092000

20102001
/// Returns the current seek position from the start of the stream.
@@ -2066,6 +2057,21 @@ pub trait Seek {
20662057
}
20672058
}
20682059

2060+
#[doc(hidden)]
2061+
#[unstable(feature = "internal_stream_len_default", issue = "none")]
2062+
pub fn stream_len_default<T: Seek + ?Sized>(self_: &mut T) -> Result<u64> {
2063+
let old_pos = self_.stream_position()?;
2064+
let len = self_.seek(SeekFrom::End(0))?;
2065+
2066+
// Avoid seeking a third time when we were already at the end of the
2067+
// stream. The branch is usually way cheaper than a seek operation.
2068+
if old_pos != len {
2069+
self_.seek(SeekFrom::Start(old_pos))?;
2070+
}
2071+
2072+
Ok(len)
2073+
}
2074+
20692075
/// Enumeration of possible methods to seek within an I/O object.
20702076
///
20712077
/// It is used by the [`Seek`] trait.

‎library/std/src/sys/pal/hermit/fs.rs

Copy file name to clipboardExpand all lines: library/std/src/sys/pal/hermit/fs.rs
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,10 @@ impl File {
426426
Err(Error::from_raw_os_error(22))
427427
}
428428

429+
pub fn size(&self) -> Option<io::Result<u64>> {
430+
None
431+
}
432+
429433
pub fn duplicate(&self) -> io::Result<File> {
430434
Err(Error::from_raw_os_error(22))
431435
}

‎library/std/src/sys/pal/solid/fs.rs

Copy file name to clipboardExpand all lines: library/std/src/sys/pal/solid/fs.rs
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,10 @@ impl File {
455455
}
456456
}
457457

458+
pub fn size(&self) -> Option<io::Result<u64>> {
459+
None
460+
}
461+
458462
pub fn duplicate(&self) -> io::Result<File> {
459463
unsupported()
460464
}

‎library/std/src/sys/pal/unix/fs.rs

Copy file name to clipboardExpand all lines: library/std/src/sys/pal/unix/fs.rs
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,6 +1307,15 @@ impl File {
13071307
Ok(n as u64)
13081308
}
13091309

1310+
pub fn size(&self) -> Option<io::Result<u64>> {
1311+
match self.file_attr().map(|attr| attr.size()) {
1312+
// Fall back to default implementation if the returned size is 0,
1313+
// we might be in a proc mount.
1314+
Ok(0) => None,
1315+
result => Some(result),
1316+
}
1317+
}
1318+
13101319
pub fn duplicate(&self) -> io::Result<File> {
13111320
self.0.duplicate().map(File)
13121321
}

‎library/std/src/sys/pal/unsupported/fs.rs

Copy file name to clipboardExpand all lines: library/std/src/sys/pal/unsupported/fs.rs
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,10 @@ impl File {
238238
self.0
239239
}
240240

241+
pub fn size(&self) -> io::Result<u64> {
242+
self.0
243+
}
244+
241245
pub fn duplicate(&self) -> io::Result<File> {
242246
self.0
243247
}

‎library/std/src/sys/pal/wasi/fs.rs

Copy file name to clipboardExpand all lines: library/std/src/sys/pal/wasi/fs.rs
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,10 @@ impl File {
465465
self.fd.seek(pos)
466466
}
467467

468+
pub fn size(&self) -> Option<io::Result<u64>> {
469+
None
470+
}
471+
468472
pub fn duplicate(&self) -> io::Result<File> {
469473
// https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-rationale.md#why-no-dup
470474
unsupported()

‎library/std/src/sys/pal/windows/c/bindings.txt

Copy file name to clipboardExpand all lines: library/std/src/sys/pal/windows/c/bindings.txt
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2336,6 +2336,7 @@ Windows.Win32.Storage.FileSystem.FlushFileBuffers
23362336
Windows.Win32.Storage.FileSystem.GetFileAttributesW
23372337
Windows.Win32.Storage.FileSystem.GetFileInformationByHandle
23382338
Windows.Win32.Storage.FileSystem.GetFileInformationByHandleEx
2339+
Windows.Win32.Storage.FileSystem.GetFileSizeEx
23392340
Windows.Win32.Storage.FileSystem.GetFileType
23402341
Windows.Win32.Storage.FileSystem.GETFINALPATHNAMEBYHANDLE_FLAGS
23412342
Windows.Win32.Storage.FileSystem.GetFinalPathNameByHandleW

‎library/std/src/sys/pal/windows/c/windows_sys.rs

Copy file name to clipboardExpand all lines: library/std/src/sys/pal/windows/c/windows_sys.rs
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,10 @@ extern "system" {
273273
) -> BOOL;
274274
}
275275
#[link(name = "kernel32")]
276+
extern "system" {
277+
pub fn GetFileSizeEx(hfile: HANDLE, lpfilesize: *mut i64) -> BOOL;
278+
}
279+
#[link(name = "kernel32")]
276280
extern "system" {
277281
pub fn GetFileType(hfile: HANDLE) -> FILE_TYPE;
278282
}

‎library/std/src/sys/pal/windows/fs.rs

Copy file name to clipboardExpand all lines: library/std/src/sys/pal/windows/fs.rs
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,12 @@ impl File {
501501
Ok(newpos as u64)
502502
}
503503

504+
pub fn size(&self) -> Option<io::Result<u64>> {
505+
let mut result = 0;
506+
Some(cvt(unsafe { c::GetFileSizeEx(self.handle.as_raw_handle(), &mut result) })
507+
.map(|_| result))
508+
}
509+
504510
pub fn duplicate(&self) -> io::Result<File> {
505511
Ok(Self { handle: self.handle.try_clone()? })
506512
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.