Skip to content

Commit 1890467

Browse files
committed
ls: ListState: Add uid/gid cache to the structure
Easier to reason about than the LazyLock/Mutex encapsulated static variables. Performance difference is not measurable, but this drops uneeded Mutex lock/unlock that were seen in samply output.
1 parent 615e684 commit 1890467

File tree

1 file changed

+36
-50
lines changed

1 file changed

+36
-50
lines changed

src/uu/ls/src/ls.rs

+36-50
Original file line numberDiff line numberDiff line change
@@ -2051,6 +2051,8 @@ fn show_dir_name(
20512051
struct ListState<'a> {
20522052
out: BufWriter<Stdout>,
20532053
style_manager: Option<StyleManager<'a>>,
2054+
uid_cache: HashMap<u32, String>,
2055+
gid_cache: HashMap<u32, String>,
20542056
}
20552057

20562058
#[allow(clippy::cognitive_complexity)]
@@ -2063,6 +2065,8 @@ pub fn list(locs: Vec<&Path>, config: &Config) -> UResult<()> {
20632065
let mut state = ListState {
20642066
out: BufWriter::new(stdout()),
20652067
style_manager: config.color.as_ref().map(StyleManager::new),
2068+
uid_cache: HashMap::new(),
2069+
gid_cache: HashMap::new(),
20662070
};
20672071

20682072
for loc in locs {
@@ -2397,10 +2401,10 @@ fn get_metadata_with_deref_opt(p_buf: &Path, dereference: bool) -> std::io::Resu
23972401
fn display_dir_entry_size(
23982402
entry: &PathData,
23992403
config: &Config,
2400-
out: &mut BufWriter<Stdout>,
2404+
state: &mut ListState,
24012405
) -> (usize, usize, usize, usize, usize, usize) {
24022406
// TODO: Cache/memorize the display_* results so we don't have to recalculate them.
2403-
if let Some(md) = entry.get_metadata(out) {
2407+
if let Some(md) = entry.get_metadata(&mut state.out) {
24042408
let (size_len, major_len, minor_len) = match display_len_or_rdev(md, config) {
24052409
SizeOrDeviceId::Device(major, minor) => {
24062410
(major.len() + minor.len() + 2usize, major.len(), minor.len())
@@ -2409,8 +2413,8 @@ fn display_dir_entry_size(
24092413
};
24102414
(
24112415
display_symlink_count(md).len(),
2412-
display_uname(md, config).len(),
2413-
display_group(md, config).len(),
2416+
display_uname(md, config, state).len(),
2417+
display_group(md, config, state).len(),
24142418
size_len,
24152419
major_len,
24162420
minor_len,
@@ -2523,7 +2527,7 @@ fn display_items(
25232527
});
25242528

25252529
if config.format == Format::Long {
2526-
let padding_collection = calculate_padding_collection(items, config, &mut state.out);
2530+
let padding_collection = calculate_padding_collection(items, config, state);
25272531

25282532
for item in items {
25292533
#[cfg(unix)]
@@ -2561,7 +2565,7 @@ fn display_items(
25612565
None
25622566
};
25632567

2564-
let padding = calculate_padding_collection(items, config, &mut state.out);
2568+
let padding = calculate_padding_collection(items, config, state);
25652569

25662570
// we need to apply normal color to non filename output
25672571
if let Some(style_manager) = &mut state.style_manager {
@@ -2813,12 +2817,12 @@ fn display_item_long(
28132817

28142818
if config.long.owner {
28152819
output_display.extend(b" ");
2816-
output_display.extend_pad_right(&display_uname(md, config), padding.uname);
2820+
output_display.extend_pad_right(&display_uname(md, config, state), padding.uname);
28172821
}
28182822

28192823
if config.long.group {
28202824
output_display.extend(b" ");
2821-
output_display.extend_pad_right(&display_group(md, config), padding.group);
2825+
output_display.extend_pad_right(&display_group(md, config, state), padding.group);
28222826
}
28232827

28242828
if config.context {
@@ -2830,7 +2834,7 @@ fn display_item_long(
28302834
// the owner, since GNU/Hurd is not currently supported by Rust.
28312835
if config.long.author {
28322836
output_display.extend(b" ");
2833-
output_display.extend_pad_right(&display_uname(md, config), padding.uname);
2837+
output_display.extend_pad_right(&display_uname(md, config, state), padding.uname);
28342838
}
28352839

28362840
match display_len_or_rdev(md, config) {
@@ -3002,67 +3006,49 @@ fn get_inode(metadata: &Metadata) -> String {
30023006
// Currently getpwuid is `linux` target only. If it's broken state.out into
30033007
// a posix-compliant attribute this can be updated...
30043008
#[cfg(unix)]
3005-
use std::sync::LazyLock;
3006-
#[cfg(unix)]
3007-
use std::sync::Mutex;
3008-
#[cfg(unix)]
30093009
use uucore::entries;
30103010
use uucore::fs::FileInformation;
30113011

30123012
#[cfg(unix)]
3013-
fn cached_uid2usr(uid: u32) -> String {
3014-
static UID_CACHE: LazyLock<Mutex<HashMap<u32, String>>> =
3015-
LazyLock::new(|| Mutex::new(HashMap::new()));
3016-
3017-
let mut uid_cache = UID_CACHE.lock().unwrap();
3018-
uid_cache
3019-
.entry(uid)
3020-
.or_insert_with(|| entries::uid2usr(uid).unwrap_or_else(|_| uid.to_string()))
3021-
.clone()
3022-
}
3023-
3024-
#[cfg(unix)]
3025-
fn display_uname(metadata: &Metadata, config: &Config) -> String {
3013+
fn display_uname(metadata: &Metadata, config: &Config, state: &mut ListState) -> String {
3014+
let uid = metadata.uid();
30263015
if config.long.numeric_uid_gid {
3027-
metadata.uid().to_string()
3016+
uid.to_string()
30283017
} else {
3029-
cached_uid2usr(metadata.uid())
3018+
state
3019+
.uid_cache
3020+
.entry(uid)
3021+
.or_insert_with(|| entries::uid2usr(uid).unwrap_or_else(|_| uid.to_string()))
3022+
.clone()
30303023
}
30313024
}
30323025

30333026
#[cfg(all(unix, not(target_os = "redox")))]
3034-
fn cached_gid2grp(gid: u32) -> String {
3035-
static GID_CACHE: LazyLock<Mutex<HashMap<u32, String>>> =
3036-
LazyLock::new(|| Mutex::new(HashMap::new()));
3037-
3038-
let mut gid_cache = GID_CACHE.lock().unwrap();
3039-
gid_cache
3040-
.entry(gid)
3041-
.or_insert_with(|| entries::gid2grp(gid).unwrap_or_else(|_| gid.to_string()))
3042-
.clone()
3043-
}
3044-
3045-
#[cfg(all(unix, not(target_os = "redox")))]
3046-
fn display_group(metadata: &Metadata, config: &Config) -> String {
3027+
fn display_group(metadata: &Metadata, config: &Config, state: &mut ListState) -> String {
3028+
let gid = metadata.gid();
30473029
if config.long.numeric_uid_gid {
3048-
metadata.gid().to_string()
3030+
gid.to_string()
30493031
} else {
3050-
cached_gid2grp(metadata.gid())
3032+
state
3033+
.gid_cache
3034+
.entry(gid)
3035+
.or_insert_with(|| entries::gid2grp(gid).unwrap_or_else(|_| gid.to_string()))
3036+
.clone()
30513037
}
30523038
}
30533039

30543040
#[cfg(target_os = "redox")]
3055-
fn display_group(metadata: &Metadata, _config: &Config) -> String {
3041+
fn display_group(metadata: &Metadata, _config: &Config, _state: &mut ListState) -> String {
30563042
metadata.gid().to_string()
30573043
}
30583044

30593045
#[cfg(not(unix))]
3060-
fn display_uname(_metadata: &Metadata, _config: &Config) -> String {
3046+
fn display_uname(_metadata: &Metadata, _config: &Config, _state: &mut ListState) -> String {
30613047
"somebody".to_string()
30623048
}
30633049

30643050
#[cfg(not(unix))]
3065-
fn display_group(_metadata: &Metadata, _config: &Config) -> String {
3051+
fn display_group(_metadata: &Metadata, _config: &Config, _state: &mut ListState) -> String {
30663052
"somegroup".to_string()
30673053
}
30683054

@@ -3439,7 +3425,7 @@ fn get_security_context(config: &Config, p_buf: &Path, must_dereference: bool) -
34393425
fn calculate_padding_collection(
34403426
items: &[PathData],
34413427
config: &Config,
3442-
out: &mut BufWriter<Stdout>,
3428+
state: &mut ListState,
34433429
) -> PaddingCollection {
34443430
let mut padding_collections = PaddingCollection {
34453431
inode: 1,
@@ -3456,7 +3442,7 @@ fn calculate_padding_collection(
34563442
for item in items {
34573443
#[cfg(unix)]
34583444
if config.inode {
3459-
let inode_len = if let Some(md) = item.get_metadata(out) {
3445+
let inode_len = if let Some(md) = item.get_metadata(&mut state.out) {
34603446
display_inode(md).len()
34613447
} else {
34623448
continue;
@@ -3465,7 +3451,7 @@ fn calculate_padding_collection(
34653451
}
34663452

34673453
if config.alloc_size {
3468-
if let Some(md) = item.get_metadata(out) {
3454+
if let Some(md) = item.get_metadata(&mut state.out) {
34693455
let block_size_len = display_size(get_block_size(md, config), config).len();
34703456
padding_collections.block_size = block_size_len.max(padding_collections.block_size);
34713457
}
@@ -3474,7 +3460,7 @@ fn calculate_padding_collection(
34743460
if config.format == Format::Long {
34753461
let context_len = item.security_context.len();
34763462
let (link_count_len, uname_len, group_len, size_len, major_len, minor_len) =
3477-
display_dir_entry_size(item, config, out);
3463+
display_dir_entry_size(item, config, state);
34783464
padding_collections.link_count = link_count_len.max(padding_collections.link_count);
34793465
padding_collections.uname = uname_len.max(padding_collections.uname);
34803466
padding_collections.group = group_len.max(padding_collections.group);

0 commit comments

Comments
 (0)