pxar: fuse: cache goodbye table for each directory on opendir and release it on releasedir
Cache not only the goodbye table for the last directory but for each opened directory. The opendir fuse callback will fill the cache with the goodbye table and releasedir will remove it from the cache. This should reduce the number of chuncks fetched from the server in some cases. Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
This commit is contained in:
parent
02491b8fc6
commit
25ad4cbf63
|
@ -86,30 +86,12 @@ struct FuseArgs {
|
|||
/// offset within the archive for the i-node given by the caller.
|
||||
struct Context {
|
||||
decoder: Decoder,
|
||||
goodbye_cache: Option<(Inode, Vec<(PxarGoodbyeItem, Offset, Offset)>)>,
|
||||
goodbye_cache: HashMap<Inode, Vec<(PxarGoodbyeItem, Offset, Offset)>>,
|
||||
attr_cache: Option<(Inode, PxarAttributes)>,
|
||||
ino_offset: Offset,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Update the goodbye table to the one corresponding to the i-node offset, both
|
||||
/// given in the `Context`.
|
||||
fn update_goodbye_cache(&mut self) -> Result<(), i32> {
|
||||
if let Some((off, _)) = self.goodbye_cache {
|
||||
if off == self.ino_offset {
|
||||
// Cache contains already the correct goodbye table
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
// Inode did not match or cache is empty, need to update the cache
|
||||
let gbt = self.decoder
|
||||
.goodbye_table(None, self.ino_offset + GOODBYE_ITEM_SIZE)
|
||||
.map_err(|_| libc::EIO)?;
|
||||
self.goodbye_cache = Some((self.ino_offset, gbt));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Lookup the goodbye item identified by `filename` and its corresponding `hash`
|
||||
///
|
||||
/// Updates the goodbye table cache to contain the table for the directory given
|
||||
|
@ -129,8 +111,8 @@ impl Context {
|
|||
filename: &CStr,
|
||||
hash: u64,
|
||||
) -> Result<(u64, PxarEntry, PxarAttributes, u64), i32> {
|
||||
self.update_goodbye_cache()?;
|
||||
if let Some((_, gbt)) = &self.goodbye_cache {
|
||||
let gbt = self.goodbye_cache.get(&self.ino_offset)
|
||||
.ok_or_else(|| libc::EIO)?;
|
||||
let mut start_idx = 0;
|
||||
let mut skip_multiple = 0;
|
||||
loop {
|
||||
|
@ -164,9 +146,6 @@ impl Context {
|
|||
skip_multiple = 1;
|
||||
}
|
||||
}
|
||||
|
||||
Err(libc::ENOENT)
|
||||
}
|
||||
}
|
||||
|
||||
/// `Session` stores a pointer to the session context and is used to mount the
|
||||
|
@ -252,16 +231,21 @@ impl Session {
|
|||
/// Options have to be provided as comma separated OsStr, e.g.
|
||||
/// ("ro,default_permissions").
|
||||
pub fn new(
|
||||
decoder: Decoder,
|
||||
mut decoder: Decoder,
|
||||
options: &OsStr,
|
||||
verbose: bool,
|
||||
) -> Result<Self, Error> {
|
||||
let args = Self::setup_args(options, verbose)?;
|
||||
let oprs = Self::setup_callbacks();
|
||||
|
||||
let root_ino_offset = decoder.root_end_offset() - GOODBYE_ITEM_SIZE;
|
||||
let root_goodbye_table = decoder.goodbye_table(None, root_ino_offset + GOODBYE_ITEM_SIZE)?;
|
||||
let mut goodbye_cache = HashMap::new();
|
||||
goodbye_cache.insert(root_ino_offset, root_goodbye_table);
|
||||
|
||||
let ctx = Context {
|
||||
decoder,
|
||||
goodbye_cache: None,
|
||||
goodbye_cache,
|
||||
attr_cache: None,
|
||||
ino_offset: 0,
|
||||
};
|
||||
|
@ -323,6 +307,7 @@ impl Session {
|
|||
oprs.read = Some(Self::read);
|
||||
oprs.opendir = Some(Self::opendir);
|
||||
oprs.readdir = Some(Self::readdir);
|
||||
oprs.releasedir = Some(Self::releasedir);
|
||||
oprs
|
||||
}
|
||||
|
||||
|
@ -518,14 +503,12 @@ impl Session {
|
|||
/// state identifies the directory as opened.
|
||||
extern "C" fn opendir(req: Request, inode: u64, fileinfo: MutPtr) {
|
||||
Self::run_in_context(req, inode, |ctx| {
|
||||
let (_, entry, _, _) = ctx
|
||||
.decoder
|
||||
.attributes(ctx.ino_offset)
|
||||
let gbt = ctx.decoder
|
||||
.goodbye_table(None, ctx.ino_offset + GOODBYE_ITEM_SIZE)
|
||||
.map_err(|_| libc::EIO)?;
|
||||
if (entry.mode as u32 & libc::S_IFMT) != libc::S_IFDIR {
|
||||
return Err(libc::ENOENT);
|
||||
}
|
||||
let _ret = unsafe { fuse_reply_open(req, fileinfo) };
|
||||
ctx.goodbye_cache.insert(ctx.ino_offset, gbt);
|
||||
|
||||
let _ret = unsafe { fuse_reply_open(req, fileinfo as MutPtr) };
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
@ -543,8 +526,8 @@ impl Session {
|
|||
let offset = offset as usize;
|
||||
|
||||
Self::run_in_context(req, inode, |ctx| {
|
||||
ctx.update_goodbye_cache()?;
|
||||
let gb_table = &ctx.goodbye_cache.as_ref().unwrap().1;
|
||||
let gb_table = ctx.goodbye_cache.get(&ctx.ino_offset)
|
||||
.ok_or_else(|| libc::EIO)?;
|
||||
let n_entries = gb_table.len();
|
||||
let mut buf = ReplyBuf::new(req, size, offset);
|
||||
|
||||
|
@ -603,6 +586,14 @@ impl Session {
|
|||
buf.reply_filled()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
extern "C" fn releasedir(req: Request, inode: u64, _fileinfo: MutPtr) {
|
||||
Self::run_in_context(req, inode, |ctx| {
|
||||
let _gbt = ctx.goodbye_cache.remove(&ctx.ino_offset);
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Session {
|
||||
|
|
Loading…
Reference in New Issue