summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2022-03-03 18:51:38 +0200
committerLars Wirzenius <liw@liw.fi>2022-03-06 09:25:56 +0200
commit0ee823e00a29ca15ac2699ec588f9c1ff2c7b04d (patch)
tree1861ca86b1577398c6af5d45d21fcc5ca7909575
parent630ef5e8aa07545daf4c6bb5b23992cdd54c1ce2 (diff)
downloadobnam2-0ee823e00a29ca15ac2699ec588f9c1ff2c7b04d.tar.gz
perf: cache user and group name lookups
Sponsored-by: author
-rw-r--r--src/fsentry.rs35
-rw-r--r--src/fsiter.rs23
-rw-r--r--src/generation.rs9
3 files changed, 38 insertions, 29 deletions
diff --git a/src/fsentry.rs b/src/fsentry.rs
index 9f40fd0..90afd70 100644
--- a/src/fsentry.rs
+++ b/src/fsentry.rs
@@ -8,6 +8,7 @@ use std::fs::{FileType, Metadata};
use std::os::unix::ffi::OsStringExt;
use std::os::unix::fs::FileTypeExt;
use std::path::{Path, PathBuf};
+use users::{Groups, Users, UsersCache};
#[cfg(target_os = "linux")]
use std::os::linux::fs::MetadataExt;
@@ -69,7 +70,11 @@ pub enum FsEntryError {
#[allow(clippy::len_without_is_empty)]
impl FilesystemEntry {
/// Create an `FsEntry` from a file's metadata.
- pub fn from_metadata(path: &Path, meta: &Metadata) -> Result<Self, FsEntryError> {
+ pub fn from_metadata(
+ path: &Path,
+ meta: &Metadata,
+ cache: &mut UsersCache,
+ ) -> Result<Self, FsEntryError> {
let kind = FilesystemKind::from_file_type(meta.file_type());
let symlink_target = if kind == FilesystemKind::Symlink {
debug!("reading symlink target for {:?}", path);
@@ -82,6 +87,16 @@ impl FilesystemEntry {
let uid = meta.st_uid();
let gid = meta.st_gid();
+ let user: String = if let Some(user) = cache.get_user_by_uid(uid) {
+ user.name().to_string_lossy().to_string()
+ } else {
+ "".to_string()
+ };
+ let group = if let Some(group) = cache.get_group_by_gid(gid) {
+ group.name().to_string_lossy().to_string()
+ } else {
+ "".to_string()
+ };
Ok(Self {
path: path.to_path_buf().into_os_string().into_vec(),
@@ -95,8 +110,8 @@ impl FilesystemEntry {
symlink_target,
uid,
gid,
- user: get_username(uid),
- group: get_groupname(gid),
+ user,
+ group,
})
}
@@ -152,20 +167,6 @@ impl FilesystemEntry {
}
}
-fn get_username(uid: u32) -> String {
- match users::get_user_by_uid(uid) {
- None => "".to_string(),
- Some(user) => user.name().to_os_string().to_string_lossy().into_owned(),
- }
-}
-
-fn get_groupname(gid: u32) -> String {
- match users::get_group_by_gid(gid) {
- None => "".to_string(),
- Some(group) => group.name().to_os_string().to_string_lossy().into_owned(),
- }
-}
-
/// Different types of file system entries.
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub enum FilesystemKind {
diff --git a/src/fsiter.rs b/src/fsiter.rs
index 2747cce..8b231c1 100644
--- a/src/fsiter.rs
+++ b/src/fsiter.rs
@@ -1,8 +1,9 @@
//! Iterate over directory tree.
use crate::fsentry::{FilesystemEntry, FsEntryError};
-use log::{debug, warn};
+use log::warn;
use std::path::{Path, PathBuf};
+use users::UsersCache;
use walkdir::{DirEntry, IntoIter, WalkDir};
/// Filesystem entry along with additional info about it.
@@ -56,6 +57,7 @@ impl Iterator for FsIterator {
/// Cachedir-aware adaptor for WalkDir: it skips the contents of dirs that contain CACHEDIR.TAG,
/// but still yields entries for the dir and the tag themselves.
struct SkipCachedirs {
+ cache: UsersCache,
iter: IntoIter,
exclude_cache_tag_directories: bool,
// This is the last tag we've found. `next()` will yield it before asking `iter` for more
@@ -66,6 +68,7 @@ struct SkipCachedirs {
impl SkipCachedirs {
fn new(iter: IntoIter, exclude_cache_tag_directories: bool) -> Self {
Self {
+ cache: UsersCache::new(),
iter,
exclude_cache_tag_directories,
cachedir_tag: None,
@@ -109,7 +112,7 @@ impl SkipCachedirs {
if content == CACHEDIR_TAG {
self.iter.skip_current_dir();
- self.cachedir_tag = Some(new_entry(&tag_path, true));
+ self.cachedir_tag = Some(new_entry(&tag_path, true, &mut self.cache));
}
}
}
@@ -120,22 +123,26 @@ impl Iterator for SkipCachedirs {
fn next(&mut self) -> Option<Self::Item> {
self.cachedir_tag.take().or_else(|| {
let next = self.iter.next();
- debug!("walkdir found: {:?}", next);
+ // debug!("walkdir found: {:?}", next);
match next {
None => None,
Some(Err(err)) => Some(Err(FsIterError::WalkDir(err))),
Some(Ok(entry)) => {
self.try_enqueue_cachedir_tag(&entry);
- Some(new_entry(entry.path(), false))
+ Some(new_entry(entry.path(), false, &mut self.cache))
}
}
})
}
}
-fn new_entry(path: &Path, is_cachedir_tag: bool) -> Result<AnnotatedFsEntry, FsIterError> {
+fn new_entry(
+ path: &Path,
+ is_cachedir_tag: bool,
+ cache: &mut UsersCache,
+) -> Result<AnnotatedFsEntry, FsIterError> {
let meta = std::fs::symlink_metadata(path);
- debug!("metadata for {:?}: {:?}", path, meta);
+ // debug!("metadata for {:?}: {:?}", path, meta);
let meta = match meta {
Ok(meta) => meta,
Err(err) => {
@@ -143,8 +150,8 @@ fn new_entry(path: &Path, is_cachedir_tag: bool) -> Result<AnnotatedFsEntry, FsI
return Err(FsIterError::Metadata(path.to_path_buf(), err));
}
};
- let entry = FilesystemEntry::from_metadata(path, &meta)?;
- debug!("FileSystemEntry for {:?}: {:?}", path, entry);
+ let entry = FilesystemEntry::from_metadata(path, &meta, cache)?;
+ // debug!("FileSystemEntry for {:?}: {:?}", path, entry);
let annotated = AnnotatedFsEntry {
inner: entry,
is_cachedir_tag,
diff --git a/src/generation.rs b/src/generation.rs
index 3950a0c..05163be 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -446,16 +446,17 @@ mod test {
let tag_path2 = Path::new("/another_dir/a_tag");
let mut gen = NascentGeneration::create(&dbfile).unwrap();
+ let mut cache = users::UsersCache::new();
gen.insert(
- FilesystemEntry::from_metadata(nontag_path1, &metadata).unwrap(),
+ FilesystemEntry::from_metadata(nontag_path1, &metadata, &mut cache).unwrap(),
&[],
Reason::IsNew,
false,
)
.unwrap();
gen.insert(
- FilesystemEntry::from_metadata(tag_path1, &metadata).unwrap(),
+ FilesystemEntry::from_metadata(tag_path1, &metadata, &mut cache).unwrap(),
&[],
Reason::IsNew,
true,
@@ -464,13 +465,13 @@ mod test {
let entries = vec![
FsEntryBackupOutcome {
- entry: FilesystemEntry::from_metadata(nontag_path2, &metadata).unwrap(),
+ entry: FilesystemEntry::from_metadata(nontag_path2, &metadata, &mut cache).unwrap(),
ids: vec![],
reason: Reason::IsNew,
is_cachedir_tag: false,
},
FsEntryBackupOutcome {
- entry: FilesystemEntry::from_metadata(tag_path2, &metadata).unwrap(),
+ entry: FilesystemEntry::from_metadata(tag_path2, &metadata, &mut cache).unwrap(),
ids: vec![],
reason: Reason::IsNew,
is_cachedir_tag: true,