@@ -13,7 +13,7 @@ const PROBE_SIZE_U32: u32 = PROBE_SIZE as u32;
1313
1414// Max bytes we can read using io uring submission at a time
1515// SAFETY: cannot be higher than u32::MAX for safe cast
16- // Set to read max 64 blocks at time
16+ // Set to read max 64 MiB at time
1717const MAX_READ_SIZE : usize = 64 * 1024 * 1024 ;
1818
1919pub ( crate ) async fn read_uring ( path : & Path ) -> io:: Result < Vec < u8 > > {
@@ -27,141 +27,111 @@ pub(crate) async fn read_uring(path: &Path) -> io::Result<Vec<u8>> {
2727 . expect ( "unexpected in-flight operation detected" )
2828 . into ( ) ;
2929
30- // extra single capacity for the whole size to fit without any reallocation
31- let buf = Vec :: with_capacity ( size_hint. unwrap_or ( 0 ) ) ;
30+ let mut buf = Vec :: new ( ) ;
3231
33- read_to_end_uring ( size_hint, fd, buf) . await
32+ if let Some ( size_hint) = size_hint {
33+ buf. try_reserve ( size_hint) ?;
34+ }
35+
36+ read_to_end_uring ( fd, buf) . await
3437}
3538
36- async fn read_to_end_uring (
37- size_hint : Option < usize > ,
38- mut fd : OwnedFd ,
39- mut buf : Vec < u8 > ,
40- ) -> io:: Result < Vec < u8 > > {
39+ async fn read_to_end_uring ( mut fd : OwnedFd , mut buf : Vec < u8 > ) -> io:: Result < Vec < u8 > > {
4140 let mut offset = 0 ;
42-
4341 let start_cap = buf. capacity ( ) ;
4442
45- // if buffer has no room and no size_hint, start with a small probe_read from 0 offset
46- if ( size_hint. is_none ( ) || size_hint == Some ( 0 ) ) && buf. capacity ( ) - buf. len ( ) < PROBE_SIZE {
47- let ( size_read, r_fd, r_buf) = small_probe_read ( fd, buf, offset) . await ?;
48-
49- if size_read == 0 {
50- return Ok ( r_buf) ;
51- }
52-
53- buf = r_buf;
54- fd = r_fd;
55- offset += size_read as u64 ;
56- }
57-
5843 loop {
59- if buf. len ( ) == buf. capacity ( ) && buf. capacity ( ) == start_cap {
44+ if buf. len ( ) == buf. capacity ( ) && buf. capacity ( ) == start_cap && buf . len ( ) > PROBE_SIZE {
6045 // The buffer might be an exact fit. Let's read into a probe buffer
6146 // and see if it returns `Ok(0)`. If so, we've avoided an
6247 // unnecessary increasing of the capacity. But if not, append the
6348 // probe buffer to the primary buffer and let its capacity grow.
64- let ( size_read, r_fd, r_buf) = small_probe_read ( fd, buf, offset) . await ?;
49+ let ( size_read, r_fd, r_buf) = small_probe_read ( fd, buf, & mut offset) . await ?;
6550
6651 if size_read == 0 {
6752 return Ok ( r_buf) ;
6853 }
6954
7055 buf = r_buf;
7156 fd = r_fd;
72- offset += size_read as u64 ;
7357 }
7458
7559 // buf is full, need more capacity
7660 if buf. len ( ) == buf. capacity ( ) {
7761 buf. try_reserve ( PROBE_SIZE ) ?;
7862 }
7963
80- // doesn't matter if we have a valid size_hint or not, if we do more
81- // than 2 consecutive_short_reads, gradually increase the buffer
82- // capacity to read more data at a time
83-
8464 // prepare the spare capacity to be read into
8565 let buf_len = usize:: min ( buf. spare_capacity_mut ( ) . len ( ) , MAX_READ_SIZE ) ;
8666
87- // SAFETY: buf_len cannot be greater than u32::MAX because max_read_size
88- // is u32::MAX
89- let mut read_len = buf_len as u32 ;
90-
91- loop {
92- // read into spare capacity
93- let ( res, r_fd, r_buf) = Op :: read ( fd, buf, read_len, offset) . await ;
94-
95- match res {
96- Ok ( 0 ) => return Ok ( r_buf) ,
97- Ok ( size_read) => {
98- fd = r_fd;
99- buf = r_buf;
100- offset += size_read as u64 ;
101- read_len -= size_read;
102-
103- // keep reading if there's something left to be read
104- if read_len > 0 {
105- continue ;
106- } else {
107- break ;
108- }
109- }
110- Err ( e) if e. kind ( ) == ErrorKind :: Interrupted => {
111- buf = r_buf;
112- fd = r_fd;
67+ // buf_len cannot be greater than u32::MAX because MAX_READ_SIZE
68+ // is less than u32::MAX
69+ let read_len = u32:: try_from ( buf_len) . expect ( "buf_len must always fit in u32" ) ;
11370
114- continue ;
115- }
116- Err ( e) => return Err ( e) ,
117- }
71+ // read into spare capacity
72+ let ( size_read, r_fd, r_buf) = op_read ( fd, buf, & mut offset, read_len) . await ?;
73+
74+ if size_read == 0 {
75+ return Ok ( r_buf) ;
11876 }
77+
78+ fd = r_fd;
79+ buf = r_buf;
11980 }
12081}
12182
12283async fn small_probe_read (
123- mut fd : OwnedFd ,
84+ fd : OwnedFd ,
12485 mut buf : Vec < u8 > ,
125- offset : u64 ,
86+ offset : & mut u64 ,
12687) -> io:: Result < ( u32 , OwnedFd , Vec < u8 > ) > {
88+ let read_len = PROBE_SIZE_U32 ;
89+
12790 let mut temp_arr = [ 0 ; PROBE_SIZE ] ;
128- let has_enough = buf. len ( ) > PROBE_SIZE ;
129-
130- if has_enough {
131- // if we have more than PROBE_SIZE bytes in the buffer already then
132- // don't call reserve as we might potentially read 0 bytes
133- let back_bytes_len = buf. len ( ) - PROBE_SIZE ;
134- temp_arr. copy_from_slice ( & buf[ back_bytes_len..] ) ;
135- // We're decreasing the length of the buffer and len is greater
136- // than PROBE_SIZE. So we can read into the discarded length
137- buf. truncate ( back_bytes_len) ;
138- } else {
139- // we don't even have PROBE_SIZE length in the buffer, we need this
140- // reservation
141- buf. reserve_exact ( PROBE_SIZE ) ;
142- }
91+ // we don't call this function if buffer's length < PROBE_SIZE
92+ let back_bytes_len = buf. len ( ) - PROBE_SIZE ;
93+
94+ temp_arr. copy_from_slice ( & buf[ back_bytes_len..] ) ;
95+
96+ // We're decreasing the length of the buffer and len is greater
97+ // than PROBE_SIZE. So we can read into the discarded length
98+ buf. truncate ( back_bytes_len) ;
14399
100+ let ( size_read, r_fd, mut r_buf) = op_read ( fd, buf, offset, read_len) . await ?;
101+ // If `size_read` returns zero due to reasons such as buffer's exact fit,
102+ // then this `try_reserve` does not perform allocation.
103+ r_buf. try_reserve ( PROBE_SIZE ) ?;
104+ r_buf. splice ( back_bytes_len..back_bytes_len, temp_arr) ;
105+
106+ Ok ( ( size_read, r_fd, r_buf) )
107+ }
108+
109+ async fn op_read (
110+ mut fd : OwnedFd ,
111+ mut buf : Vec < u8 > ,
112+ offset : & mut u64 ,
113+ mut read_len : u32 ,
114+ ) -> io:: Result < ( u32 , OwnedFd , Vec < u8 > ) > {
144115 loop {
145- let ( res, r_fd, mut r_buf) = Op :: read ( fd, buf, PROBE_SIZE_U32 , offset) . await ;
116+ let ( res, r_fd, r_buf) = Op :: read ( fd, buf, read_len , * offset) . await ;
146117
147118 match res {
148- // return early if we inserted into reserved PROBE_SIZE
149- // bytes
150- Ok ( size_read) if !has_enough => return Ok ( ( size_read, r_fd, r_buf) ) ,
119+ Err ( e) if e. kind ( ) == ErrorKind :: Interrupted => {
120+ buf = r_buf;
121+ fd = r_fd;
122+ }
123+ Err ( e) => return Err ( e) ,
151124 Ok ( size_read) => {
152- let old_len = r_buf. len ( ) - ( size_read as usize ) ;
125+ * offset += size_read as u64 ;
126+ read_len -= size_read;
153127
154- r_buf. splice ( old_len..old_len, temp_arr) ;
128+ if read_len == 0 || size_read == 0 {
129+ return Ok ( ( size_read, r_fd, r_buf) ) ;
130+ }
155131
156- return Ok ( ( size_read, r_fd, r_buf) ) ;
157- }
158- Err ( e) if e. kind ( ) == ErrorKind :: Interrupted => {
159132 buf = r_buf;
160133 fd = r_fd;
161-
162- continue ;
163134 }
164- Err ( e) => return Err ( e) ,
165135 }
166136 }
167137}
0 commit comments