parquet/util/
push_buffers.rs1use crate::errors::ParquetError;
19use crate::file::reader::{ChunkReader, Length};
20use bytes::Bytes;
21use std::fmt::Display;
22use std::ops::Range;
23
24#[derive(Debug, Clone, Default)]
45pub struct PushBuffers {
46 offset: u64,
48 file_len: u64,
50 ranges: Vec<Range<u64>>,
52 buffers: Vec<Bytes>,
54}
55
56impl Display for PushBuffers {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 writeln!(
59 f,
60 "Buffers (offset: {}, file_len: {})",
61 self.offset, self.file_len
62 )?;
63 writeln!(f, "Available Ranges (w/ offset):")?;
64 for range in &self.ranges {
65 writeln!(
66 f,
67 " {}..{} ({}..{}): {} bytes",
68 range.start,
69 range.end,
70 range.start + self.offset,
71 range.end + self.offset,
72 range.end - range.start
73 )?;
74 }
75
76 Ok(())
77 }
78}
79
80impl PushBuffers {
81 pub fn new(file_len: u64) -> Self {
87 Self {
88 offset: 0,
89 file_len,
90 ranges: Vec::new(),
91 buffers: Vec::new(),
92 }
93 }
94
95 pub fn push_ranges(
102 &mut self,
103 ranges: Vec<Range<u64>>,
104 buffers: Vec<Bytes>,
105 ) -> Result<(), ParquetError> {
106 if ranges.len() != buffers.len() {
107 return Err(general_err!(
108 "Number of ranges ({}) must match number of buffers ({})",
109 ranges.len(),
110 buffers.len()
111 ));
112 }
113 for (range, buffer) in ranges.into_iter().zip(buffers) {
114 self.push_range(range, buffer)?;
115 }
116 Ok(())
117 }
118
119 pub fn push_range(&mut self, range: Range<u64>, buffer: Bytes) -> Result<(), ParquetError> {
125 let expected = range.end.saturating_sub(range.start);
126 if expected != buffer.len() as u64 {
127 return Err(general_err!(
128 "Buffer length ({}) does not match length ({}) of range {}..{}",
129 buffer.len(),
130 expected,
131 range.start,
132 range.end
133 ));
134 }
135 self.ranges.push(range);
136 self.buffers.push(buffer);
137 Ok(())
138 }
139
140 pub(crate) fn has_range(&self, range: &Range<u64>) -> bool {
142 self.ranges
143 .iter()
144 .any(|r| r.start <= range.start && r.end >= range.end)
145 }
146
147 fn iter(&self) -> impl Iterator<Item = (&Range<u64>, &Bytes)> {
148 self.ranges.iter().zip(self.buffers.iter())
149 }
150
151 pub(crate) fn file_len(&self) -> u64 {
153 self.file_len
154 }
155
156 fn with_offset(mut self, offset: u64) -> Self {
158 self.offset = offset;
159 self
160 }
161
162 #[cfg(feature = "arrow")]
164 pub(crate) fn buffered_bytes(&self) -> u64 {
165 self.ranges.iter().map(|r| r.end - r.start).sum()
166 }
167
168 #[cfg(feature = "arrow")]
170 pub(crate) fn clear_ranges(&mut self, ranges_to_clear: &[Range<u64>]) {
171 let mut new_ranges = Vec::new();
172 let mut new_buffers = Vec::new();
173
174 for (range, buffer) in self.iter() {
175 if !ranges_to_clear
176 .iter()
177 .any(|r| r.start == range.start && r.end == range.end)
178 {
179 new_ranges.push(range.clone());
180 new_buffers.push(buffer.clone());
181 }
182 }
183 self.ranges = new_ranges;
184 self.buffers = new_buffers;
185 }
186
187 pub(crate) fn clear_all_ranges(&mut self) {
189 self.ranges.clear();
190 self.buffers.clear();
191 }
192}
193
194impl Length for PushBuffers {
195 fn len(&self) -> u64 {
196 self.file_len
197 }
198}
199
200impl std::io::Read for PushBuffers {
202 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
203 let mut found = false;
205 for (range, data) in self.iter() {
206 if range.start <= self.offset && range.end >= self.offset + buf.len() as u64 {
207 let start_offset = (self.offset - range.start) as usize;
209 let end_offset = start_offset + buf.len();
210 let slice = data.slice(start_offset..end_offset);
211 buf.copy_from_slice(slice.as_ref());
212 found = true;
213 break;
214 }
215 }
216 if found {
217 self.offset += buf.len() as u64;
220 Ok(buf.len())
221 } else {
222 Err(std::io::Error::new(
223 std::io::ErrorKind::UnexpectedEof,
224 "No data available in Buffers",
225 ))
226 }
227 }
228}
229
230impl ChunkReader for PushBuffers {
231 type T = Self;
232
233 fn get_read(&self, start: u64) -> Result<Self::T, ParquetError> {
234 Ok(self.clone().with_offset(self.offset + start))
235 }
236
237 fn get_bytes(&self, start: u64, length: usize) -> Result<Bytes, ParquetError> {
238 for (range, data) in self.iter() {
240 if range.start <= start && range.end >= start + length as u64 {
241 let start_offset = (start - range.start) as usize;
243 return Ok(data.slice(start_offset..start_offset + length));
244 }
245 }
246 let requested_end = start + length as u64;
248 Err(ParquetError::NeedMoreDataRange(start..requested_end))
249 }
250}
251
252#[cfg(test)]
253mod tests {
254 use super::*;
255
256 #[test]
257 fn push_range_accepts_matching_length() {
258 let mut buffers = PushBuffers::new(100);
259 buffers
260 .push_range(10..14, Bytes::from_static(b"abcd"))
261 .unwrap();
262 assert!(buffers.has_range(&(10..14)));
263 }
264
265 #[test]
266 fn push_range_rejects_short_buffer() {
267 let mut buffers = PushBuffers::new(100);
268 let err = buffers
269 .push_range(10..20, Bytes::from_static(b"abcd"))
270 .unwrap_err();
271 assert_eq!(
272 err.to_string(),
273 "Parquet error: Buffer length (4) does not match length (10) of range 10..20"
274 );
275 assert!(!buffers.has_range(&(10..20)));
276 }
277
278 #[test]
279 fn push_ranges_rejects_mismatched_counts() {
280 let mut buffers = PushBuffers::new(100);
281 let err = buffers
282 .push_ranges(vec![0..4, 4..8], vec![Bytes::from_static(b"abcd")])
283 .unwrap_err();
284 assert_eq!(
285 err.to_string(),
286 "Parquet error: Number of ranges (2) must match number of buffers (1)"
287 );
288 }
289}