1use std::io::{self, SeekFrom};
2use std::pin::Pin;
3use std::sync::Arc;
4use std::task::{Context, Poll};
5use std::time::Duration;
6
7use bytes::{BufMut, Bytes, BytesMut};
8use futures::stream::BoxStream;
9use futures::{Stream, StreamExt, stream};
10use log::warn;
11use tokio::io::{AsyncRead, AsyncSeek, ReadBuf};
12use tokio::runtime::Handle;
13
14use crate::common::config::Configuration;
15use crate::ec::{EcSchema, resolve_ec_policy};
16use crate::hdfs::block_reader::get_block_stream;
17use crate::hdfs::block_writer::BlockWriter;
18use crate::hdfs::crypto::FileCryptoCodec;
19use crate::hdfs::protocol::{LeaseTracker, NamenodeProtocol};
20use crate::proto::hdfs;
21use crate::{HdfsError, Result};
22
23const COMPLETE_RETRY_DELAY_MS: u64 = 500;
24const COMPLETE_RETRIES: u32 = 5;
25
26fn io_error(error: HdfsError) -> io::Error {
27 io::Error::other(error)
28}
29
30struct PendingRead {
31 stream: BoxStream<'static, Result<Bytes>>,
32 end_position: usize,
33}
34
35pub struct FileReader {
36 protocol: Arc<NamenodeProtocol>,
37 located_blocks: hdfs::LocatedBlocksProto,
38 ec_schema: Option<EcSchema>,
39 position: usize,
40 config: Arc<Configuration>,
41 handle: Handle,
42 pending_read: Option<std::sync::Mutex<PendingRead>>,
43 crypto: Option<Arc<FileCryptoCodec>>,
44}
45
46impl FileReader {
47 pub(crate) fn new(
48 protocol: Arc<NamenodeProtocol>,
49 located_blocks: hdfs::LocatedBlocksProto,
50 ec_schema: Option<EcSchema>,
51 config: Arc<Configuration>,
52 handle: Handle,
53 crypto: Option<Arc<FileCryptoCodec>>,
54 ) -> Self {
55 Self {
56 protocol,
57 located_blocks,
58 ec_schema,
59 position: 0,
60 config,
61 handle,
62 pending_read: None,
63 crypto,
64 }
65 }
66
67 pub fn file_length(&self) -> usize {
69 self.located_blocks.file_length as usize
70 }
71
72 pub fn remaining(&self) -> usize {
74 if self.position > self.file_length() {
75 0
76 } else {
77 self.file_length() - self.position
78 }
79 }
80
81 pub fn set_position(&mut self, pos: usize) {
83 if pos > self.file_length() {
84 panic!("Cannot seek beyond the end of a file");
85 }
86 self.pending_read = None;
87 self.position = pos;
88 }
89
90 pub fn tell(&self) -> usize {
92 self.position
93 }
94
95 pub async fn read_bytes(&mut self, len: usize) -> Result<Bytes> {
98 self.pending_read = None;
99 if self.position >= self.file_length() {
100 Ok(Bytes::new())
101 } else {
102 let offset = self.position;
103 self.position = usize::min(self.position + len, self.file_length());
104 self.read_range(offset, self.position - offset).await
105 }
106 }
107
108 pub async fn read_into(&mut self, buf: &mut [u8]) -> Result<usize> {
111 self.pending_read = None;
112 if self.position >= self.file_length() {
113 Ok(0)
114 } else {
115 let offset = self.position;
116 self.position = usize::min(self.position + buf.len(), self.file_length());
117 let read_bytes = self.position - offset;
118 self.read_range_buf(&mut buf[..read_bytes], offset).await?;
119 Ok(read_bytes)
120 }
121 }
122
123 pub async fn read_range(&self, offset: usize, len: usize) -> Result<Bytes> {
128 let mut stream = self.read_range_stream(offset, len);
129 let mut buf = BytesMut::with_capacity(len);
130 while let Some(bytes) = stream.next().await.transpose()? {
131 buf.put(bytes);
132 }
133 Ok(buf.freeze())
134 }
135
136 pub async fn read_range_buf(&self, mut buf: &mut [u8], offset: usize) -> Result<()> {
140 let mut stream = self.read_range_stream(offset, buf.len());
141 while let Some(bytes) = stream.next().await.transpose()? {
142 buf.put(bytes);
143 }
144
145 Ok(())
146 }
147
148 pub fn read_range_stream(
152 &self,
153 offset: usize,
154 len: usize,
155 ) -> impl Stream<Item = Result<Bytes>> + use<> {
156 if offset + len > self.file_length() {
157 panic!("Cannot read past end of the file");
158 }
159
160 let block_streams: Vec<BoxStream<Result<Bytes>>> = self
161 .located_blocks
162 .blocks
163 .iter()
164 .flat_map(move |block| {
165 let block_file_start = block.offset as usize;
166 let block_file_end = block_file_start + block.b.num_bytes() as usize;
167
168 if block_file_start < (offset + len) && block_file_end > offset {
169 let block_start = offset - usize::min(offset, block_file_start);
171 let block_end = usize::min(offset + len, block_file_end) - block_file_start;
172 Some(get_block_stream(
173 Arc::clone(&self.protocol),
174 block.clone(),
175 block_start,
176 block_end - block_start,
177 self.ec_schema.clone(),
178 Arc::clone(&self.config),
179 self.handle.clone(),
180 self.crypto.clone(),
181 ))
182 } else {
183 None
185 }
186 })
187 .collect();
188
189 stream::iter(block_streams).flatten()
190 }
191}
192
193impl AsyncRead for FileReader {
194 fn poll_read(
195 mut self: Pin<&mut Self>,
196 cx: &mut Context<'_>,
197 buf: &mut ReadBuf<'_>,
198 ) -> Poll<io::Result<()>> {
199 if buf.remaining() == 0 {
200 return Poll::Ready(Ok(()));
201 }
202
203 let starting_len = buf.filled().len();
204
205 loop {
206 if self.pending_read.is_none() {
207 if self.position >= self.file_length() {
208 return Poll::Ready(Ok(()));
209 }
210
211 let offset = self.position;
212 let len = usize::min(buf.remaining(), self.file_length() - self.position);
213 let stream = self.read_range_stream(offset, len).boxed();
214 self.pending_read = Some(std::sync::Mutex::new(PendingRead {
215 stream,
216 end_position: offset + len,
217 }));
218 }
219
220 let poll_result = {
221 let mut pending = self.pending_read.as_ref().unwrap().lock().unwrap();
222 Pin::new(&mut pending.stream).poll_next(cx)
223 };
224
225 match poll_result {
226 Poll::Ready(Some(Ok(bytes))) => {
227 self.position += bytes.len();
228 buf.put_slice(&bytes);
229
230 if self.pending_read.as_ref().is_some_and(|pending| {
231 self.position >= pending.lock().unwrap().end_position
232 }) {
233 self.pending_read = None;
234 }
235
236 if buf.remaining() == 0 {
237 return Poll::Ready(Ok(()));
238 }
239 }
240 Poll::Ready(Some(Err(error))) => {
241 self.pending_read = None;
242 return Poll::Ready(Err(io_error(error)));
243 }
244 Poll::Ready(None) => {
245 self.pending_read = None;
246 return Poll::Ready(Ok(()));
247 }
248 Poll::Pending => {
249 if buf.filled().len() > starting_len {
250 return Poll::Ready(Ok(()));
251 }
252 return Poll::Pending;
253 }
254 }
255 }
256 }
257}
258
259impl AsyncSeek for FileReader {
260 fn start_seek(mut self: Pin<&mut Self>, position: SeekFrom) -> io::Result<()> {
261 let file_length = self.file_length() as i128;
262 let current = self.tell() as i128;
263 let new_pos = match position {
264 SeekFrom::Start(pos) => i128::from(pos),
265 SeekFrom::End(offset) => file_length + i128::from(offset),
266 SeekFrom::Current(offset) => current + i128::from(offset),
267 };
268
269 if new_pos < 0 || new_pos > file_length {
270 return Err(io::Error::new(
271 io::ErrorKind::InvalidInput,
272 "cannot seek outside of file bounds",
273 ));
274 }
275
276 self.set_position(new_pos as usize);
277 Ok(())
278 }
279
280 fn poll_complete(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
281 Poll::Ready(Ok(self.tell() as u64))
282 }
283}
284
285pub struct FileWriter {
286 src: String,
287 protocol: Arc<NamenodeProtocol>,
288 status: hdfs::HdfsFileStatusProto,
289 config: Arc<Configuration>,
290 handle: Handle,
291 block_writer: Option<BlockWriter>,
292 last_block: Option<hdfs::LocatedBlockProto>,
293 closed: bool,
294 bytes_written: usize,
295 crypto: Option<Arc<FileCryptoCodec>>,
296}
297
298impl FileWriter {
299 #[allow(clippy::too_many_arguments)]
300 pub(crate) fn new(
301 protocol: Arc<NamenodeProtocol>,
302 src: String,
303 status: hdfs::HdfsFileStatusProto,
304 config: Arc<Configuration>,
305 handle: Handle,
306 last_block: Option<hdfs::LocatedBlockProto>,
308 crypto: Option<Arc<FileCryptoCodec>>,
309 ) -> Self {
310 protocol.add_file_lease(status.file_id(), status.namespace.clone());
311 Self {
312 protocol,
313 src,
314 status,
315 config,
316 handle,
317 block_writer: None,
318 last_block,
319 closed: false,
320 bytes_written: 0,
321 crypto,
322 }
323 }
324
325 async fn create_block_writer(&mut self) -> Result<()> {
326 let new_block = if let Some(last_block) = self.last_block.take() {
327 if last_block.b.num_bytes() < self.status.blocksize() && self.status.ec_policy.is_none()
329 {
330 last_block
332 } else {
333 self.protocol
335 .add_block(&self.src, Some(last_block.b), self.status.file_id)
336 .await?
337 .block
338 }
339 } else {
340 let extended_block = if let Some(block_writer) = self.block_writer.take() {
343 Some(block_writer.close().await?)
344 } else {
345 None
346 };
347
348 self.protocol
349 .add_block(&self.src, extended_block, self.status.file_id)
350 .await?
351 .block
352 };
353
354 let block_writer = BlockWriter::new(
355 Arc::clone(&self.protocol),
356 new_block,
357 self.protocol.get_cached_server_defaults().await?,
358 Arc::clone(&self.config),
359 self.handle.clone(),
360 self.status
361 .ec_policy
362 .as_ref()
363 .map(resolve_ec_policy)
364 .transpose()?
365 .as_ref(),
366 &self.src,
367 &self.status,
368 self.crypto.clone(),
369 )
370 .await?;
371
372 self.block_writer = Some(block_writer);
373 Ok(())
374 }
375
376 async fn get_block_writer(&mut self) -> Result<&mut BlockWriter> {
377 if self.block_writer.as_ref().is_some_and(|b| b.is_full()) || self.block_writer.is_none() {
379 self.create_block_writer().await?;
380 }
381
382 Ok(self.block_writer.as_mut().unwrap())
383 }
384
385 pub async fn write_bytes(&mut self, mut buf: Bytes) -> Result<usize> {
386 let bytes_to_write = buf.len();
387 while !buf.is_empty() {
388 let block_writer = self.get_block_writer().await?;
389
390 block_writer.write(&mut buf).await?;
391 }
392
393 self.bytes_written += bytes_to_write;
394
395 Ok(bytes_to_write)
396 }
397
398 pub async fn close(&mut self) -> Result<()> {
399 if !self.closed {
400 let extended_block = if let Some(block_writer) = self.block_writer.take() {
401 Some(block_writer.close().await?)
402 } else {
403 None
404 };
405
406 let mut retry_delay = COMPLETE_RETRY_DELAY_MS;
407 let mut retries = 0;
408 while retries < COMPLETE_RETRIES {
409 let successful = self
410 .protocol
411 .complete(&self.src, extended_block.clone(), self.status.file_id)
412 .await?
413 .result;
414
415 if successful {
416 self.closed = true;
417 return Ok(());
418 }
419
420 let sleep = {
422 let _guard = self.handle.enter();
423 tokio::time::sleep(Duration::from_millis(retry_delay))
424 };
425 sleep.await;
426
427 retry_delay *= 2;
428 retries += 1;
429 }
430 Err(HdfsError::OperationFailed(
431 "Failed to complete file in time".to_string(),
432 ))
433 } else {
434 Ok(())
435 }
436 }
437}
438
439impl Drop for FileWriter {
440 fn drop(&mut self) {
441 if !self.closed {
442 warn!(
443 "FileWriter dropped without being closed. File content may not have saved or may not be complete"
444 );
445 }
446
447 self.protocol
448 .remove_file_lease(self.status.file_id(), self.status.namespace.clone());
449 }
450}