mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-07 05:43:14 +00:00
use filereader as asyncread
This commit is contained in:
@@ -49,7 +49,8 @@ use common::defer;
|
||||
use path_absolutize::Absolutize;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::Debug;
|
||||
use std::io::Cursor;
|
||||
use std::io::SeekFrom;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, SystemTime};
|
||||
@@ -59,7 +60,7 @@ use std::{
|
||||
};
|
||||
use time::OffsetDateTime;
|
||||
use tokio::fs::{self, File};
|
||||
use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt, ErrorKind};
|
||||
use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWrite, AsyncWriteExt, ErrorKind};
|
||||
use tokio::sync::mpsc::Sender;
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::{error, info, warn};
|
||||
@@ -735,13 +736,24 @@ impl LocalDisk {
|
||||
sum: &[u8],
|
||||
shard_size: usize,
|
||||
) -> Result<()> {
|
||||
let mut file = utils::fs::open_file(part_path, O_CREATE | O_WRONLY)
|
||||
let file = utils::fs::open_file(part_path, O_CREATE | O_WRONLY)
|
||||
.await
|
||||
.map_err(os_err_to_file_err)?;
|
||||
|
||||
let mut data = Vec::new();
|
||||
let n = file.read_to_end(&mut data).await?;
|
||||
bitrot_verify(&mut Cursor::new(data), n, part_size, algo, sum.to_vec(), shard_size)
|
||||
// let mut data = Vec::new();
|
||||
// let n = file.read_to_end(&mut data).await?;
|
||||
|
||||
let meta = file.metadata().await?;
|
||||
|
||||
bitrot_verify(
|
||||
FileReader::Local(LocalFileReader::new(file)),
|
||||
meta.size() as usize,
|
||||
part_size,
|
||||
algo,
|
||||
sum.to_vec(),
|
||||
shard_size,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn scan_dir<W: AsyncWrite + Unpin>(
|
||||
@@ -1533,6 +1545,50 @@ impl DiskAPI for LocalDisk {
|
||||
Ok(FileReader::Local(LocalFileReader::new(f)))
|
||||
}
|
||||
|
||||
async fn read_file_stream(&self, volume: &str, path: &str, offset: usize, length: usize) -> Result<FileReader> {
|
||||
let volume_dir = self.get_bucket_path(volume)?;
|
||||
if !skip_access_checks(volume) {
|
||||
if let Err(e) = utils::fs::access(&volume_dir).await {
|
||||
return Err(convert_access_error(e, DiskError::VolumeAccessDenied));
|
||||
}
|
||||
}
|
||||
|
||||
let file_path = volume_dir.join(Path::new(&path));
|
||||
check_path_length(file_path.to_string_lossy().to_string().as_str())?;
|
||||
|
||||
let mut f = self.open_file(file_path, O_RDONLY, volume_dir).await.map_err(|err| {
|
||||
if let Some(e) = err.to_io_err() {
|
||||
if os_is_not_exist(&e) {
|
||||
Error::new(DiskError::FileNotFound)
|
||||
} else if os_is_permission(&e) || is_sys_err_not_dir(&e) {
|
||||
Error::new(DiskError::FileAccessDenied)
|
||||
} else if is_sys_err_io(&e) {
|
||||
Error::new(DiskError::FaultyDisk)
|
||||
} else if is_sys_err_too_many_files(&e) {
|
||||
Error::new(DiskError::TooManyOpenFiles)
|
||||
} else {
|
||||
Error::new(e)
|
||||
}
|
||||
} else {
|
||||
err
|
||||
}
|
||||
})?;
|
||||
|
||||
let meta = f.metadata().await?;
|
||||
if meta.len() < (offset + length) as u64 {
|
||||
error!(
|
||||
"read_file_stream: file size is less than offset + length {} + {} = {}",
|
||||
offset,
|
||||
length,
|
||||
meta.len()
|
||||
);
|
||||
return Err(Error::new(DiskError::FileCorrupt));
|
||||
}
|
||||
|
||||
f.seek(SeekFrom::Start(offset as u64)).await?;
|
||||
|
||||
Ok(FileReader::Local(LocalFileReader::new(f)))
|
||||
}
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
async fn list_dir(&self, origvolume: &str, volume: &str, dir_path: &str, count: i32) -> Result<Vec<String>> {
|
||||
if !origvolume.is_empty() {
|
||||
|
||||
+300
-142
@@ -28,28 +28,24 @@ use crate::{
|
||||
store_api::{FileInfo, ObjectInfo, RawFileInfo},
|
||||
utils::path::SLASH_SEPARATOR,
|
||||
};
|
||||
|
||||
use endpoint::Endpoint;
|
||||
use error::DiskError;
|
||||
use futures::StreamExt;
|
||||
use local::LocalDisk;
|
||||
use madmin::info_commands::DiskMetrics;
|
||||
use protos::proto_gen::node_service::{
|
||||
node_service_client::NodeServiceClient, ReadAtRequest, ReadAtResponse, WriteRequest, WriteResponse,
|
||||
};
|
||||
use protos::proto_gen::node_service::{node_service_client::NodeServiceClient, WriteRequest, WriteResponse};
|
||||
use remote::RemoteDisk;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
any::Any,
|
||||
cmp::Ordering,
|
||||
fmt::Debug,
|
||||
io::{Cursor, SeekFrom},
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
};
|
||||
use std::io::Read as _;
|
||||
use std::pin::Pin;
|
||||
use std::task::Poll;
|
||||
use std::{any::Any, cmp::Ordering, fmt::Debug, io::Cursor, path::PathBuf, sync::Arc};
|
||||
use time::OffsetDateTime;
|
||||
use tokio::io::AsyncRead;
|
||||
use tokio::{
|
||||
fs::File,
|
||||
io::{AsyncReadExt, AsyncSeekExt, AsyncWrite, AsyncWriteExt},
|
||||
io::{AsyncWrite, AsyncWriteExt},
|
||||
sync::mpsc::{self, Sender},
|
||||
};
|
||||
use tokio_stream::wrappers::ReceiverStream;
|
||||
@@ -206,6 +202,13 @@ impl DiskAPI for Disk {
|
||||
}
|
||||
}
|
||||
|
||||
async fn read_file_stream(&self, volume: &str, path: &str, offset: usize, length: usize) -> Result<FileReader> {
|
||||
match self {
|
||||
Disk::Local(local_disk) => local_disk.read_file_stream(volume, path, offset, length).await,
|
||||
Disk::Remote(remote_disk) => remote_disk.read_file_stream(volume, path, offset, length).await,
|
||||
}
|
||||
}
|
||||
|
||||
async fn list_dir(&self, _origvolume: &str, volume: &str, _dir_path: &str, _count: i32) -> Result<Vec<String>> {
|
||||
match self {
|
||||
Disk::Local(local_disk) => local_disk.list_dir(_origvolume, volume, _dir_path, _count).await,
|
||||
@@ -451,6 +454,7 @@ pub trait DiskAPI: Debug + Send + Sync + 'static {
|
||||
// 读目录下的所有文件、目录
|
||||
async fn list_dir(&self, origvolume: &str, volume: &str, dir_path: &str, count: i32) -> Result<Vec<String>>;
|
||||
async fn read_file(&self, volume: &str, path: &str) -> Result<FileReader>;
|
||||
async fn read_file_stream(&self, volume: &str, path: &str, offset: usize, length: usize) -> Result<FileReader>;
|
||||
async fn append_file(&self, volume: &str, path: &str) -> Result<FileWriter>;
|
||||
async fn create_file(&self, origvolume: &str, volume: &str, path: &str, file_size: usize) -> Result<FileWriter>;
|
||||
// ReadFileStream
|
||||
@@ -1411,186 +1415,340 @@ impl Writer for RemoteFileWriter {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait Reader {
|
||||
async fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<usize>;
|
||||
async fn seek(&mut self, offset: usize) -> Result<()>;
|
||||
async fn read_exact(&mut self, buf: &mut [u8]) -> Result<usize>;
|
||||
}
|
||||
// #[async_trait::async_trait]
|
||||
// pub trait Reader {
|
||||
// async fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<usize>;
|
||||
// // async fn seek(&mut self, offset: usize) -> Result<()>;
|
||||
// // async fn read_exact(&mut self, buf: &mut [u8]) -> Result<usize>;
|
||||
// }
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FileReader {
|
||||
Local(LocalFileReader),
|
||||
Remote(RemoteFileReader),
|
||||
// Remote(RemoteFileReader),
|
||||
Buffer(BufferReader),
|
||||
Http(HttpFileReader),
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Reader for FileReader {
|
||||
async fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
match self {
|
||||
Self::Local(reader) => reader.read_at(offset, buf).await,
|
||||
Self::Remote(reader) => reader.read_at(offset, buf).await,
|
||||
Self::Buffer(reader) => reader.read_at(offset, buf).await,
|
||||
}
|
||||
}
|
||||
async fn seek(&mut self, offset: usize) -> Result<()> {
|
||||
match self {
|
||||
Self::Local(reader) => reader.seek(offset).await,
|
||||
Self::Remote(reader) => reader.seek(offset).await,
|
||||
Self::Buffer(reader) => reader.seek(offset).await,
|
||||
}
|
||||
}
|
||||
async fn read_exact(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
match self {
|
||||
Self::Local(reader) => reader.read_exact(buf).await,
|
||||
Self::Remote(reader) => reader.read_exact(buf).await,
|
||||
Self::Buffer(reader) => reader.read_exact(buf).await,
|
||||
impl AsyncRead for FileReader {
|
||||
#[tracing::instrument(level = "debug", skip(self, buf))]
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
buf: &mut tokio::io::ReadBuf<'_>,
|
||||
) -> std::task::Poll<std::result::Result<(), std::io::Error>> {
|
||||
match &mut *self {
|
||||
Self::Local(reader) => Pin::new(&mut reader.inner).poll_read(cx, buf),
|
||||
Self::Buffer(reader) => Pin::new(&mut reader.inner).poll_read(cx, buf),
|
||||
Self::Http(reader) => Pin::new(reader).poll_read(cx, buf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #[async_trait::async_trait]
|
||||
// impl Reader for FileReader {
|
||||
// async fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
// match self {
|
||||
// Self::Local(reader) => reader.read_at(offset, buf).await,
|
||||
// Self::Remote(reader) => reader.read_at(offset, buf).await,
|
||||
// Self::Buffer(reader) => reader.read_at(offset, buf).await,
|
||||
// Self::Http(reader) => reader.read_at(offset, buf).await,
|
||||
// }
|
||||
// }
|
||||
// // async fn seek(&mut self, offset: usize) -> Result<()> {
|
||||
// // match self {
|
||||
// // Self::Local(reader) => reader.seek(offset).await,
|
||||
// // Self::Remote(reader) => reader.seek(offset).await,
|
||||
// // Self::Buffer(reader) => reader.seek(offset).await,
|
||||
// // }
|
||||
// // }
|
||||
// // async fn read_exact(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
// // match self {
|
||||
// // Self::Local(reader) => reader.read_exact(buf).await,
|
||||
// // Self::Remote(reader) => reader.read_exact(buf).await,
|
||||
// // Self::Buffer(reader) => reader.read_exact(buf).await,
|
||||
// // }
|
||||
// // }
|
||||
// }
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BufferReader {
|
||||
pub inner: Cursor<Vec<u8>>,
|
||||
pos: usize,
|
||||
remaining: usize,
|
||||
}
|
||||
|
||||
impl BufferReader {
|
||||
pub fn new(inner: Vec<u8>) -> Self {
|
||||
pub fn new(inner: Vec<u8>, offset: usize, read_length: usize) -> Self {
|
||||
let mut cur = Cursor::new(inner);
|
||||
cur.set_position(offset as u64);
|
||||
Self {
|
||||
inner: Cursor::new(inner),
|
||||
pos: 0,
|
||||
inner: cur,
|
||||
remaining: offset + read_length,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Reader for BufferReader {
|
||||
impl AsyncRead for BufferReader {
|
||||
#[tracing::instrument(level = "debug", skip(self, buf))]
|
||||
async fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
self.seek(offset).await?;
|
||||
self.read_exact(buf).await
|
||||
}
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
async fn seek(&mut self, offset: usize) -> Result<()> {
|
||||
if self.pos != offset {
|
||||
self.inner.set_position(offset as u64);
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
buf: &mut tokio::io::ReadBuf<'_>,
|
||||
) -> std::task::Poll<std::result::Result<(), std::io::Error>> {
|
||||
match Pin::new(&mut self.inner).poll_read(cx, buf) {
|
||||
Poll::Ready(Ok(_)) => {
|
||||
if self.inner.position() as usize >= self.remaining {
|
||||
self.remaining -= buf.filled().len();
|
||||
Poll::Ready(Ok(()))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
async fn read_exact(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
let bytes_read = self.inner.read_exact(buf).await?;
|
||||
self.pos += buf.len();
|
||||
Ok(bytes_read)
|
||||
}
|
||||
}
|
||||
|
||||
// #[async_trait::async_trait]
|
||||
// impl Reader for BufferReader {
|
||||
// #[tracing::instrument(level = "debug", skip(self, buf))]
|
||||
// async fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
// if self.pos != offset {
|
||||
// self.inner.set_position(offset as u64);
|
||||
// }
|
||||
// self.inner.read_exact(buf).await?;
|
||||
// self.pos += buf.len();
|
||||
// Ok(buf.len())
|
||||
// }
|
||||
// // #[tracing::instrument(level = "debug", skip(self))]
|
||||
// // async fn seek(&mut self, offset: usize) -> Result<()> {
|
||||
// // if self.pos != offset {
|
||||
// // self.inner.set_position(offset as u64);
|
||||
// // }
|
||||
|
||||
// // Ok(())
|
||||
// // }
|
||||
// // #[tracing::instrument(level = "debug", skip(self))]
|
||||
// // async fn read_exact(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
// // let bytes_read = self.inner.read_exact(buf).await?;
|
||||
// // self.pos += buf.len();
|
||||
// // Ok(bytes_read)
|
||||
// // }
|
||||
// }
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LocalFileReader {
|
||||
pub inner: File,
|
||||
pos: usize,
|
||||
// pos: usize,
|
||||
}
|
||||
|
||||
impl LocalFileReader {
|
||||
pub fn new(inner: File) -> Self {
|
||||
Self { inner, pos: 0 }
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Reader for LocalFileReader {
|
||||
#[tracing::instrument(level = "debug", skip(self, buf))]
|
||||
async fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
self.seek(offset).await?;
|
||||
self.read_exact(buf).await
|
||||
}
|
||||
// #[async_trait::async_trait]
|
||||
// impl Reader for LocalFileReader {
|
||||
// #[tracing::instrument(level = "debug", skip(self, buf))]
|
||||
// async fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
// if self.pos != offset {
|
||||
// self.inner.seek(SeekFrom::Start(offset as u64)).await?;
|
||||
// self.pos = offset;
|
||||
// }
|
||||
// self.inner.read_exact(buf).await?;
|
||||
// self.pos += buf.len();
|
||||
// Ok(buf.len())
|
||||
// }
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
async fn seek(&mut self, offset: usize) -> Result<()> {
|
||||
if self.pos != offset {
|
||||
self.inner.seek(SeekFrom::Start(offset as u64)).await?;
|
||||
self.pos = offset;
|
||||
}
|
||||
// // #[tracing::instrument(level = "debug", skip(self))]
|
||||
// // async fn seek(&mut self, offset: usize) -> Result<()> {
|
||||
// // if self.pos != offset {
|
||||
// // self.inner.seek(SeekFrom::Start(offset as u64)).await?;
|
||||
// // self.pos = offset;
|
||||
// // }
|
||||
|
||||
Ok(())
|
||||
}
|
||||
// // Ok(())
|
||||
// // }
|
||||
// // #[tracing::instrument(level = "debug", skip(self, buf))]
|
||||
// // async fn read_exact(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
// // let bytes_read = self.inner.read_exact(buf).await?;
|
||||
// // self.pos += buf.len();
|
||||
// // Ok(bytes_read)
|
||||
// // }
|
||||
// }
|
||||
|
||||
impl AsyncRead for LocalFileReader {
|
||||
#[tracing::instrument(level = "debug", skip(self, buf))]
|
||||
async fn read_exact(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
let bytes_read = self.inner.read_exact(buf).await?;
|
||||
self.pos += buf.len();
|
||||
Ok(bytes_read)
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
buf: &mut tokio::io::ReadBuf<'_>,
|
||||
) -> std::task::Poll<std::result::Result<(), std::io::Error>> {
|
||||
Pin::new(&mut self.inner).poll_read(cx, buf)
|
||||
}
|
||||
}
|
||||
|
||||
// #[derive(Debug)]
|
||||
// pub struct RemoteFileReader {
|
||||
// pub endpoint: Endpoint,
|
||||
// pub volume: String,
|
||||
// pub path: String,
|
||||
// tx: Sender<ReadAtRequest>,
|
||||
// resp_stream: Streaming<ReadAtResponse>,
|
||||
// }
|
||||
|
||||
// impl RemoteFileReader {
|
||||
// pub async fn new(endpoint: Endpoint, volume: String, path: String, mut client: NodeClient) -> Result<Self> {
|
||||
// let (tx, rx) = mpsc::channel(128);
|
||||
// let in_stream = ReceiverStream::new(rx);
|
||||
|
||||
// let response = client.read_at(in_stream).await.unwrap();
|
||||
|
||||
// let resp_stream = response.into_inner();
|
||||
|
||||
// Ok(Self {
|
||||
// endpoint,
|
||||
// volume,
|
||||
// path,
|
||||
// tx,
|
||||
// resp_stream,
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[async_trait::async_trait]
|
||||
// impl Reader for RemoteFileReader {
|
||||
// async fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
// let request = ReadAtRequest {
|
||||
// disk: self.endpoint.to_string(),
|
||||
// volume: self.volume.to_string(),
|
||||
// path: self.path.to_string(),
|
||||
// offset: offset.try_into().unwrap(),
|
||||
// // length: length.try_into().unwrap(),
|
||||
// length: buf.len().try_into().unwrap(),
|
||||
// };
|
||||
// self.tx.send(request).await?;
|
||||
|
||||
// if let Some(resp) = self.resp_stream.next().await {
|
||||
// let resp = resp?;
|
||||
// if resp.success {
|
||||
// info!("read at stream success");
|
||||
|
||||
// buf.copy_from_slice(&resp.data);
|
||||
|
||||
// Ok(resp.read_size.try_into().unwrap())
|
||||
// } else {
|
||||
// return if let Some(err) = &resp.error {
|
||||
// Err(proto_err_to_err(err))
|
||||
// } else {
|
||||
// Err(Error::from_string(""))
|
||||
// };
|
||||
// }
|
||||
// } else {
|
||||
// let error_info = "can not get response";
|
||||
// info!("read at stream failed: {}", error_info);
|
||||
// Err(Error::from_string(error_info))
|
||||
// }
|
||||
// }
|
||||
// // async fn seek(&mut self, _offset: usize) -> Result<()> {
|
||||
// // unimplemented!()
|
||||
// // }
|
||||
// // async fn read_exact(&mut self, _buf: &mut [u8]) -> Result<usize> {
|
||||
// // unimplemented!()
|
||||
// // }
|
||||
// }
|
||||
|
||||
// impl AsyncRead for RemoteFileReader {
|
||||
// #[tracing::instrument(level = "debug", skip(self, buf))]
|
||||
// fn poll_read(
|
||||
// mut self: Pin<&mut Self>,
|
||||
// cx: &mut std::task::Context<'_>,
|
||||
// buf: &mut tokio::io::ReadBuf<'_>,
|
||||
// ) -> std::task::Poll<std::result::Result<(), std::io::Error>> {
|
||||
// unimplemented!("poll_read")
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RemoteFileReader {
|
||||
pub endpoint: Endpoint,
|
||||
pub volume: String,
|
||||
pub path: String,
|
||||
tx: Sender<ReadAtRequest>,
|
||||
resp_stream: Streaming<ReadAtResponse>,
|
||||
pub struct HttpFileReader {
|
||||
// client: reqwest::Client,
|
||||
// url: String,
|
||||
// disk: String,
|
||||
// volume: String,
|
||||
// path: String,
|
||||
// offset: usize,
|
||||
// length: usize,
|
||||
inner: reqwest::blocking::Response,
|
||||
// buf: Vec<u8>,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl RemoteFileReader {
|
||||
pub async fn new(endpoint: Endpoint, volume: String, path: String, mut client: NodeClient) -> Result<Self> {
|
||||
let (tx, rx) = mpsc::channel(128);
|
||||
let in_stream = ReceiverStream::new(rx);
|
||||
|
||||
let response = client.read_at(in_stream).await.unwrap();
|
||||
|
||||
let resp_stream = response.into_inner();
|
||||
|
||||
impl HttpFileReader {
|
||||
pub async fn new(url: &str, disk: &str, volume: &str, path: &str, offset: usize, length: usize) -> Result<Self> {
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let resp = client
|
||||
.get(format!(
|
||||
"{}/rustfs/rpc/read_file_stream?disk={}&volume={}&path={}&offset={}&length={}",
|
||||
url, disk, volume, path, offset, length
|
||||
))
|
||||
.send()?;
|
||||
Ok(Self {
|
||||
endpoint,
|
||||
volume,
|
||||
path,
|
||||
tx,
|
||||
resp_stream,
|
||||
// client: reqwest::Client::new(),
|
||||
// url: url.to_string(),
|
||||
// disk: disk.to_string(),
|
||||
// volume: volume.to_string(),
|
||||
// path: path.to_string(),
|
||||
// offset,
|
||||
// length,
|
||||
inner: resp,
|
||||
// buf: Vec::new(),
|
||||
pos: 0,
|
||||
})
|
||||
}
|
||||
|
||||
// pub async fn get_response(&self) -> Result<&Response, std::io::Error> {
|
||||
// if let Some(resp) = self.inner.get() {
|
||||
// return Ok(resp);
|
||||
// } else {
|
||||
// let client = reqwest::Client::new();
|
||||
// let resp = client
|
||||
// .get(&format!(
|
||||
// "{}/read_file_stream?disk={}&volume={}&path={}&offset={}&length={}",
|
||||
// self.url, self.disk, self.volume, self.path, self.offset, self.length
|
||||
// ))
|
||||
// .send()
|
||||
// .await
|
||||
// .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
|
||||
// self.inner.set(resp);
|
||||
// Ok(self.inner.get().unwrap())
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Reader for RemoteFileReader {
|
||||
async fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
let request = ReadAtRequest {
|
||||
disk: self.endpoint.to_string(),
|
||||
volume: self.volume.to_string(),
|
||||
path: self.path.to_string(),
|
||||
offset: offset.try_into().unwrap(),
|
||||
// length: length.try_into().unwrap(),
|
||||
length: buf.len().try_into().unwrap(),
|
||||
};
|
||||
self.tx.send(request).await?;
|
||||
|
||||
if let Some(resp) = self.resp_stream.next().await {
|
||||
let resp = resp?;
|
||||
if resp.success {
|
||||
info!("read at stream success");
|
||||
|
||||
buf.copy_from_slice(&resp.data);
|
||||
|
||||
Ok(resp.read_size.try_into().unwrap())
|
||||
} else {
|
||||
return if let Some(err) = &resp.error {
|
||||
Err(proto_err_to_err(err))
|
||||
} else {
|
||||
Err(Error::from_string(""))
|
||||
};
|
||||
}
|
||||
} else {
|
||||
let error_info = "can not get response";
|
||||
info!("read at stream failed: {}", error_info);
|
||||
Err(Error::from_string(error_info))
|
||||
}
|
||||
}
|
||||
async fn seek(&mut self, _offset: usize) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
async fn read_exact(&mut self, _buf: &mut [u8]) -> Result<usize> {
|
||||
unimplemented!()
|
||||
impl AsyncRead for HttpFileReader {
|
||||
#[tracing::instrument(level = "debug", skip(self, buf))]
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
buf: &mut tokio::io::ReadBuf<'_>,
|
||||
) -> std::task::Poll<std::result::Result<(), std::io::Error>> {
|
||||
let buf = buf.initialize_unfilled();
|
||||
self.inner.read_exact(buf)?;
|
||||
self.pos += buf.len();
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
// impl Reader for HttpFileReader {
|
||||
// async fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
// if self.pos != offset {
|
||||
// self.inner.seek(SeekFrom::Start(offset as u64))?;
|
||||
// self.pos = offset;
|
||||
// }
|
||||
// let bytes_read = self.inner.read(buf)?;
|
||||
// self.pos += bytes_read;
|
||||
// Ok(bytes_read)
|
||||
// }
|
||||
// }
|
||||
|
||||
+18
-11
@@ -23,10 +23,9 @@ use uuid::Uuid;
|
||||
|
||||
use super::{
|
||||
endpoint::Endpoint, CheckPartsResp, DeleteOptions, DiskAPI, DiskInfo, DiskInfoOptions, DiskLocation, DiskOption,
|
||||
FileInfoVersions, FileReader, FileWriter, ReadMultipleReq, ReadMultipleResp, ReadOptions, RemoteFileReader, RemoteFileWriter,
|
||||
RenameDataResp, UpdateMetadataOpts, VolumeInfo, WalkDirOptions,
|
||||
FileInfoVersions, FileReader, FileWriter, ReadMultipleReq, ReadMultipleResp, ReadOptions, RemoteFileWriter, RenameDataResp,
|
||||
UpdateMetadataOpts, VolumeInfo, WalkDirOptions,
|
||||
};
|
||||
use crate::utils::proto_err_to_err;
|
||||
use crate::{
|
||||
disk::error::DiskError,
|
||||
error::{Error, Result},
|
||||
@@ -37,6 +36,7 @@ use crate::{
|
||||
},
|
||||
store_api::{FileInfo, RawFileInfo},
|
||||
};
|
||||
use crate::{disk::HttpFileReader, utils::proto_err_to_err};
|
||||
use crate::{disk::MetaCacheEntry, metacache::writer::MetacacheWriter};
|
||||
use protos::proto_gen::node_service::RenamePartRequst;
|
||||
|
||||
@@ -346,14 +346,21 @@ impl DiskAPI for RemoteDisk {
|
||||
|
||||
async fn read_file(&self, volume: &str, path: &str) -> Result<FileReader> {
|
||||
info!("read_file");
|
||||
Ok(FileReader::Remote(
|
||||
RemoteFileReader::new(
|
||||
self.endpoint.clone(),
|
||||
volume.to_string(),
|
||||
path.to_string(),
|
||||
node_service_time_out_client(&self.addr)
|
||||
.await
|
||||
.map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?,
|
||||
Ok(FileReader::Http(
|
||||
HttpFileReader::new(self.endpoint.grid_host().as_str(), self.endpoint.to_string().as_str(), volume, path, 0, 0)
|
||||
.await?,
|
||||
))
|
||||
}
|
||||
|
||||
async fn read_file_stream(&self, volume: &str, path: &str, offset: usize, length: usize) -> Result<FileReader> {
|
||||
Ok(FileReader::Http(
|
||||
HttpFileReader::new(
|
||||
self.endpoint.grid_host().as_str(),
|
||||
self.endpoint.to_string().as_str(),
|
||||
volume,
|
||||
path,
|
||||
offset,
|
||||
length,
|
||||
)
|
||||
.await?,
|
||||
))
|
||||
|
||||
Reference in New Issue
Block a user