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

Sign up
Appearance settings

Commit c141cbf

Browse files
Rollup merge of #125087 - tbu-:pr_file_stream_len, r=ChrisDenton
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.
2 parents ccf3198 + 4b1e28b commit c141cbf

File tree

11 files changed

+90
-11
lines changed

11 files changed

+90
-11
lines changed

‎library/std/src/fs.rs‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,9 +1311,39 @@ impl Write for &File {
13111311
}
13121312
#[stable(feature = "rust1", since = "1.0.0")]
13131313
impl Seek for &File {
1314+
/// Seek to an offset, in bytes in a file.
1315+
///
1316+
/// See [`Seek::seek`] docs for more info.
1317+
///
1318+
/// # Platform-specific behavior
1319+
///
1320+
/// This function currently corresponds to the `lseek64` function on Unix
1321+
/// and the `SetFilePointerEx` function on Windows. Note that this [may
1322+
/// change in the future][changes].
1323+
///
1324+
/// [changes]: io#platform-specific-behavior
13141325
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
13151326
self.inner.seek(pos)
13161327
}
1328+
1329+
/// Returns the length of this file (in bytes).
1330+
///
1331+
/// See [`Seek::stream_len`] docs for more info.
1332+
///
1333+
/// # Platform-specific behavior
1334+
///
1335+
/// This function currently corresponds to the `statx` function on Linux
1336+
/// (with fallbacks) and the `GetFileSizeEx` function on Windows. Note that
1337+
/// this [may change in the future][changes].
1338+
///
1339+
/// [changes]: io#platform-specific-behavior
1340+
fn stream_len(&mut self) -> io::Result<u64> {
1341+
if let Some(result) = self.inner.size() {
1342+
return result;
1343+
}
1344+
io::stream_len_default(self)
1345+
}
1346+
13171347
fn stream_position(&mut self) -> io::Result<u64> {
13181348
self.inner.tell()
13191349
}
@@ -1363,6 +1393,9 @@ impl Seek for File {
13631393
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
13641394
(&*self).seek(pos)
13651395
}
1396+
fn stream_len(&mut self) -> io::Result<u64> {
1397+
(&*self).stream_len()
1398+
}
13661399
fn stream_position(&mut self) -> io::Result<u64> {
13671400
(&*self).stream_position()
13681401
}
@@ -1412,6 +1445,9 @@ impl Seek for Arc<File> {
14121445
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
14131446
(&**self).seek(pos)
14141447
}
1448+
fn stream_len(&mut self) -> io::Result<u64> {
1449+
(&**self).stream_len()
1450+
}
14151451
fn stream_position(&mut self) -> io::Result<u64> {
14161452
(&**self).stream_position()
14171453
}

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

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2028,7 +2028,7 @@ pub trait Seek {
20282028

20292029
/// Returns the length of this stream (in bytes).
20302030
///
2031-
/// This method is implemented using up to three seek operations. If this
2031+
/// The default implementation uses up to three seek operations. If this
20322032
/// method returns successfully, the seek position is unchanged (i.e. the
20332033
/// position before calling this method is the same as afterwards).
20342034
/// However, if this method returns an error, the seek position is
@@ -2062,16 +2062,7 @@ pub trait Seek {
20622062
/// ```
20632063
#[unstable(feature = "seek_stream_len", issue = "59359")]
20642064
fn stream_len(&mut self) -> Result<u64> {
2065-
let old_pos = self.stream_position()?;
2066-
let len = self.seek(SeekFrom::End(0))?;
2067-
2068-
// Avoid seeking a third time when we were already at the end of the
2069-
// stream. The branch is usually way cheaper than a seek operation.
2070-
if old_pos != len {
2071-
self.seek(SeekFrom::Start(old_pos))?;
2072-
}
2073-
2074-
Ok(len)
2065+
stream_len_default(self)
20752066
}
20762067

20772068
/// Returns the current seek position from the start of the stream.
@@ -2132,6 +2123,19 @@ pub trait Seek {
21322123
}
21332124
}
21342125

2126+
pub(crate) fn stream_len_default<T: Seek + ?Sized>(self_: &mut T) -> Result<u64> {
2127+
let old_pos = self_.stream_position()?;
2128+
let len = self_.seek(SeekFrom::End(0))?;
2129+
2130+
// Avoid seeking a third time when we were already at the end of the
2131+
// stream. The branch is usually way cheaper than a seek operation.
2132+
if old_pos != len {
2133+
self_.seek(SeekFrom::Start(old_pos))?;
2134+
}
2135+
2136+
Ok(len)
2137+
}
2138+
21352139
/// Enumeration of possible methods to seek within an I/O object.
21362140
///
21372141
/// It is used by the [`Seek`] trait.

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,10 @@ impl File {
422422
self.0.seek(pos)
423423
}
424424

425+
pub fn size(&self) -> Option<io::Result<u64>> {
426+
None
427+
}
428+
425429
pub fn tell(&self) -> io::Result<u64> {
426430
self.0.tell()
427431
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,10 @@ impl File {
459459
self.tell()
460460
}
461461

462+
pub fn size(&self) -> Option<io::Result<u64>> {
463+
None
464+
}
465+
462466
pub fn tell(&self) -> io::Result<u64> {
463467
unsafe {
464468
let mut out_offset = MaybeUninit::uninit();

‎library/std/src/sys/fs/uefi.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,10 @@ impl File {
280280
self.0
281281
}
282282

283+
pub fn size(&self) -> Option<io::Result<u64>> {
284+
self.0
285+
}
286+
283287
pub fn tell(&self) -> io::Result<u64> {
284288
self.0
285289
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1464,6 +1464,15 @@ impl File {
14641464
Ok(n as u64)
14651465
}
14661466

1467+
pub fn size(&self) -> Option<io::Result<u64>> {
1468+
match self.file_attr().map(|attr| attr.size()) {
1469+
// Fall back to default implementation if the returned size is 0,
1470+
// we might be in a proc mount.
1471+
Ok(0) => None,
1472+
result => Some(result),
1473+
}
1474+
}
1475+
14671476
pub fn tell(&self) -> io::Result<u64> {
14681477
self.seek(SeekFrom::Current(0))
14691478
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,10 @@ impl File {
259259
self.0
260260
}
261261

262+
pub fn size(&self) -> Option<io::Result<u64>> {
263+
self.0
264+
}
265+
262266
pub fn tell(&self) -> io::Result<u64> {
263267
self.0
264268
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,10 @@ impl File {
516516
self.fd.seek(pos)
517517
}
518518

519+
pub fn size(&self) -> Option<io::Result<u64>> {
520+
None
521+
}
522+
519523
pub fn tell(&self) -> io::Result<u64> {
520524
self.fd.tell()
521525
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,14 @@ impl File {
616616
Ok(newpos as u64)
617617
}
618618

619+
pub fn size(&self) -> Option<io::Result<u64>> {
620+
let mut result = 0;
621+
Some(
622+
cvt(unsafe { c::GetFileSizeEx(self.handle.as_raw_handle(), &mut result) })
623+
.map(|_| result as u64),
624+
)
625+
}
626+
619627
pub fn tell(&self) -> io::Result<u64> {
620628
self.seek(SeekFrom::Current(0))
621629
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2156,6 +2156,7 @@ GetExitCodeProcess
21562156
GetFileAttributesW
21572157
GetFileInformationByHandle
21582158
GetFileInformationByHandleEx
2159+
GetFileSizeEx
21592160
GetFileType
21602161
GETFINALPATHNAMEBYHANDLE_FLAGS
21612162
GetFinalPathNameByHandleW

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /