pxar: Improve read performance for fuse.
By storing the payload start offset in the `DirectoryEntry` and passing this information to `Decoder::read()`, the payload can be read directly and a repeated re-reading of the entry information is avoided. Signed-off-by: Christian Ebner <c.ebner@proxmox.com> Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
032d3ad80f
commit
63698e720c
@ -33,6 +33,8 @@ pub struct DirectoryEntry {
|
|||||||
pub size: u64,
|
pub size: u64,
|
||||||
/// Target path for symbolic links
|
/// Target path for symbolic links
|
||||||
pub target: Option<PathBuf>,
|
pub target: Option<PathBuf>,
|
||||||
|
/// Start offset of the payload if present.
|
||||||
|
pub payload_offset: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait to create ReadSeek Decoder trait objects.
|
/// Trait to create ReadSeek Decoder trait objects.
|
||||||
@ -68,9 +70,9 @@ impl Decoder {
|
|||||||
check_ca_header::<PxarEntry>(&header, PXAR_ENTRY)?;
|
check_ca_header::<PxarEntry>(&header, PXAR_ENTRY)?;
|
||||||
let entry: PxarEntry = self.inner.read_item()?;
|
let entry: PxarEntry = self.inner.read_item()?;
|
||||||
let (header, xattr) = self.inner.read_attributes()?;
|
let (header, xattr) = self.inner.read_attributes()?;
|
||||||
let size = match header.htype {
|
let (size, payload_offset) = match header.htype {
|
||||||
PXAR_PAYLOAD => header.size - HEADER_SIZE,
|
PXAR_PAYLOAD => (header.size - HEADER_SIZE, Some(self.seek(SeekFrom::Current(0))?)),
|
||||||
_ => 0,
|
_ => (0, None),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(DirectoryEntry {
|
Ok(DirectoryEntry {
|
||||||
@ -81,6 +83,7 @@ impl Decoder {
|
|||||||
xattr,
|
xattr,
|
||||||
size,
|
size,
|
||||||
target: None,
|
target: None,
|
||||||
|
payload_offset,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,9 +137,9 @@ impl Decoder {
|
|||||||
check_ca_header::<PxarEntry>(&head, PXAR_ENTRY)?;
|
check_ca_header::<PxarEntry>(&head, PXAR_ENTRY)?;
|
||||||
let entry: PxarEntry = self.inner.read_item()?;
|
let entry: PxarEntry = self.inner.read_item()?;
|
||||||
let (header, xattr) = self.inner.read_attributes()?;
|
let (header, xattr) = self.inner.read_attributes()?;
|
||||||
let size = match header.htype {
|
let (size, payload_offset) = match header.htype {
|
||||||
PXAR_PAYLOAD => header.size - HEADER_SIZE,
|
PXAR_PAYLOAD => (header.size - HEADER_SIZE, Some(self.seek(SeekFrom::Current(0))?)),
|
||||||
_ => 0,
|
_ => (0, None),
|
||||||
};
|
};
|
||||||
let target = match header.htype {
|
let target = match header.htype {
|
||||||
PXAR_SYMLINK => Some(self.inner.read_link(header.size)?),
|
PXAR_SYMLINK => Some(self.inner.read_link(header.size)?),
|
||||||
@ -151,6 +154,7 @@ impl Decoder {
|
|||||||
xattr,
|
xattr,
|
||||||
size,
|
size,
|
||||||
target,
|
target,
|
||||||
|
payload_offset,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,45 +339,26 @@ impl Decoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read the payload of the file given by `offset`.
|
/// Read the payload of the file given by `entry`.
|
||||||
///
|
///
|
||||||
/// This will read the file by first seeking to `offset` within the archive,
|
/// This will read a files payload as raw bytes starting from `offset` after
|
||||||
/// check if there is indeed a valid item with payload and then read `size`
|
/// the payload marker, reading `size` bytes.
|
||||||
/// bytes of content starting from `data_offset`.
|
/// If the payload from `offset` to EOF is smaller than `size` bytes, the
|
||||||
/// If EOF is reached before reading `size` bytes, the reduced buffer is
|
/// buffer with reduced size is returned.
|
||||||
/// returned.
|
/// If `offset` is larger than the payload size of the `DirectoryEntry`, an
|
||||||
pub fn read(&mut self, offset: u64, size: usize, data_offset: u64) -> Result<Vec<u8>, Error> {
|
/// empty buffer is returned.
|
||||||
self.seek(SeekFrom::Start(offset))?;
|
pub fn read(&mut self, entry: &DirectoryEntry, size: usize, offset: u64) -> Result<Vec<u8>, Error> {
|
||||||
let head: PxarHeader = self.inner.read_item()?;
|
let start_offset = entry.payload_offset
|
||||||
if head.htype != PXAR_FILENAME {
|
.ok_or_else(|| format_err!("entry has no payload offset"))?;
|
||||||
bail!("Expected PXAR_FILENAME, encountered 0x{:x?}", head.htype);
|
if offset >= entry.size {
|
||||||
}
|
|
||||||
let _filename = self.inner.read_filename(head.size)?;
|
|
||||||
|
|
||||||
let head: PxarHeader = self.inner.read_item()?;
|
|
||||||
if head.htype == PXAR_FORMAT_HARDLINK {
|
|
||||||
let (_, diff) = self.inner.read_hardlink(head.size)?;
|
|
||||||
return self.read(offset - diff, size, data_offset);
|
|
||||||
}
|
|
||||||
check_ca_header::<PxarEntry>(&head, PXAR_ENTRY)?;
|
|
||||||
let _: PxarEntry = self.inner.read_item()?;
|
|
||||||
|
|
||||||
let (header, _) = self.inner.read_attributes()?;
|
|
||||||
if header.htype != PXAR_PAYLOAD {
|
|
||||||
bail!("Expected PXAR_PAYLOAD, found 0x{:x?}", header.htype);
|
|
||||||
}
|
|
||||||
|
|
||||||
let payload_size = header.size - HEADER_SIZE;
|
|
||||||
if data_offset >= payload_size {
|
|
||||||
return Ok(Vec::new());
|
return Ok(Vec::new());
|
||||||
}
|
}
|
||||||
|
let len = if u64::try_from(size)? > entry.size {
|
||||||
let len = if data_offset + u64::try_from(size)? > payload_size {
|
usize::try_from(entry.size)?
|
||||||
usize::try_from(payload_size - data_offset)?
|
|
||||||
} else {
|
} else {
|
||||||
size
|
size
|
||||||
};
|
};
|
||||||
self.inner.skip_bytes(usize::try_from(data_offset)?)?;
|
self.seek(SeekFrom::Start(start_offset + offset))?;
|
||||||
let data = self.inner.get_reader_mut().read_exact_allocated(len)?;
|
let data = self.inner.get_reader_mut().read_exact_allocated(len)?;
|
||||||
|
|
||||||
Ok(data)
|
Ok(data)
|
||||||
|
@ -538,8 +538,11 @@ impl Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn read(req: Request, inode: u64, size: size_t, offset: c_int, _fileinfo: MutPtr) {
|
extern "C" fn read(req: Request, inode: u64, size: size_t, offset: c_int, _fileinfo: MutPtr) {
|
||||||
Self::run_in_context(req, inode, |ctx| {
|
Self::run_with_context_refs(req, inode, |decoder, map, _gbt_cache, entry_cache, ino_offset| {
|
||||||
let mut data = ctx.decoder.read(ctx.ino_offset, size, offset as u64).map_err(|_| libc::EIO)?;
|
let entry = entry_cache.access(ino_offset, &mut EntryCacher { decoder, map })
|
||||||
|
.map_err(|_| libc::EIO)?
|
||||||
|
.ok_or_else(|| libc::EIO)?;
|
||||||
|
let mut data = decoder.read(&entry, size, offset as u64).map_err(|_| libc::EIO)?;
|
||||||
|
|
||||||
let _res = unsafe {
|
let _res = unsafe {
|
||||||
let len = data.len();
|
let len = data.len();
|
||||||
|
Loading…
Reference in New Issue
Block a user