pxar::fuse: Refactor lookup in order to cache accessed entries.
Context::find_goodbye_entry() is removed and incorporated into the lookup callback in order to take advantage of the entry_cache and since it is only used inside this callback. All entries read on lookup are cached. Signed-off-by: Christian Ebner <c.ebner@proxmox.com> Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
		
				
					committed by
					
						 Wolfgang Bumiller
						Wolfgang Bumiller
					
				
			
			
				
	
			
			
			
						parent
						
							63698e720c
						
					
				
				
					commit
					3e69abef02
				
			
							
								
								
									
										102
									
								
								src/pxar/fuse.rs
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								src/pxar/fuse.rs
									
									
									
									
									
								
							| @ -135,59 +135,6 @@ impl Context { | ||||
|     ) { | ||||
|         ( &mut self.decoder, &mut self.start_end_parent, &mut self.gbt_cache, &mut self.entry_cache ) | ||||
|     } | ||||
|  | ||||
|     /// Lookup the goodbye item identified by `filename` and its corresponding `hash` | ||||
|     /// | ||||
|     /// Updates the goodbye table cache to contain the table for the directory given | ||||
|     /// by the i-node in the provided `Context`. | ||||
|     /// Search the first matching `hash` in the goodbye table, allowing for a fast | ||||
|     /// comparison with the items. | ||||
|     /// As there could be a hash collision, the found items filename is then compared | ||||
|     /// by seek to the corresponding item in the archive and reading its attributes | ||||
|     /// (which the lookup callback needs to do anyway). | ||||
|     /// If the filename does not match, the function is called recursively with the | ||||
|     /// rest of the goodbye table to lookup the next match. | ||||
|     /// The matching items archive offset, entry and payload size are returned. | ||||
|     /// If there is no entry with matching `filename` and `hash` a `libc::ENOENT` is | ||||
|     /// returned. | ||||
|     fn find_goodbye_entry( | ||||
|         &mut self, | ||||
|         filename: &CStr, | ||||
|         hash: u64, | ||||
|     ) -> Result<(u64, DirectoryEntry), i32> { | ||||
|         let ino_offset = self.ino_offset; | ||||
|         let (decoder, map, gbt_cache, _) = self.as_mut_refs(); | ||||
|         let gbt = gbt_cache.access(ino_offset, &mut GbtCacher { decoder, map }) | ||||
|             .map_err(|_| libc::EIO)? | ||||
|             .ok_or_else(|| libc::ENOENT)?; | ||||
|         let mut start_idx = 0; | ||||
|         let mut skip_multiple = 0; | ||||
|         loop { | ||||
|             // Search for the next goodbye entry with matching hash. | ||||
|             let idx = search_binary_tree_by( | ||||
|                 start_idx, | ||||
|                 gbt.len(), | ||||
|                 skip_multiple, | ||||
|                 |idx| hash.cmp(&gbt[idx].0.hash), | ||||
|             ).ok_or(libc::ENOENT)?; | ||||
|  | ||||
|             let (_item, start, end) = &gbt[idx]; | ||||
|             map.insert(*start, (*end, ino_offset)); | ||||
|  | ||||
|             let entry = decoder.read_directory_entry(*start, *end) | ||||
|                 .map_err(|_| libc::EIO)?; | ||||
|  | ||||
|             // Possible hash collision, need to check if the found entry is indeed | ||||
|             // the filename to lookup. | ||||
|             if entry.filename.as_bytes() == filename.to_bytes() { | ||||
|                 return Ok((*start, entry)); | ||||
|             } | ||||
|             // Hash collision, check the next entry in the goodbye table by starting | ||||
|             // from given index but skipping one more match (so hash at index itself). | ||||
|             start_idx = idx; | ||||
|             skip_multiple = 1; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// `Session` stores a pointer to the session context and is used to mount the | ||||
| @ -490,20 +437,47 @@ impl Session  { | ||||
|         let filename = unsafe { CStr::from_ptr(name) }; | ||||
|         let hash = super::format_definition::compute_goodbye_hash(filename.to_bytes()); | ||||
|  | ||||
|         Self::run_in_context(req, parent, |ctx| { | ||||
|             let (offset, entry) = ctx.find_goodbye_entry(&filename, hash)?; | ||||
|         Self::run_with_context_refs(req, parent, |decoder, map, gbt_cache, entry_cache, ino_offset| { | ||||
|             let gbt = gbt_cache.access(ino_offset, &mut GbtCacher { decoder, map }) | ||||
|                 .map_err(|_| libc::EIO)? | ||||
|                 .ok_or_else(|| libc::EIO)?; | ||||
|             let mut start_idx = 0; | ||||
|             let mut skip_multiple = 0; | ||||
|             loop { | ||||
|                 // Search for the next goodbye entry with matching hash. | ||||
|                 let idx = search_binary_tree_by( | ||||
|                     start_idx, | ||||
|                     gbt.len(), | ||||
|                     skip_multiple, | ||||
|                     |idx| hash.cmp(&gbt[idx].0.hash), | ||||
|                 ).ok_or_else(|| libc::ENOENT)?; | ||||
|  | ||||
|             let e = EntryParam { | ||||
|                 inode: offset, | ||||
|                 generation: 1, | ||||
|                 attr: stat(offset, &entry)?, | ||||
|                 attr_timeout: std::f64::MAX, | ||||
|                 entry_timeout: std::f64::MAX, | ||||
|             }; | ||||
|                 let (_item, start, end) = &gbt[idx]; | ||||
|                 map.insert(*start, (*end, ino_offset)); | ||||
|  | ||||
|             let _res = unsafe { fuse_reply_entry(req, Some(&e)) }; | ||||
|                 let entry = entry_cache.access(*start, &mut EntryCacher { decoder, map }) | ||||
|                     .map_err(|_| libc::EIO)? | ||||
|                     .ok_or_else(|| libc::ENOENT)?; | ||||
|  | ||||
|             Ok(()) | ||||
|                 // Possible hash collision, need to check if the found entry is indeed | ||||
|                 // the filename to lookup. | ||||
|                 if entry.filename.as_bytes() == filename.to_bytes() { | ||||
|                     let e = EntryParam { | ||||
|                         inode: *start, | ||||
|                         generation: 1, | ||||
|                         attr: stat(*start, &entry)?, | ||||
|                         attr_timeout: std::f64::MAX, | ||||
|                         entry_timeout: std::f64::MAX, | ||||
|                     }; | ||||
|  | ||||
|                     let _res = unsafe { fuse_reply_entry(req, Some(&e)) }; | ||||
|                     return Ok(()) | ||||
|                 } | ||||
|                 // Hash collision, check the next entry in the goodbye table by starting | ||||
|                 // from given index but skipping one more match (so hash at index itself). | ||||
|                 start_idx = idx; | ||||
|                 skip_multiple = 1; | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user