Преглед изворни кода

Cache user and group names

I checked strace and it was reading /etc/passwd every time it needed to
look up a user or group. Now it only does it once per.
Ben S пре 11 година
родитељ
комит
b5a1b24bda
3 измењених фајлова са 40 додато и 19 уклоњено
  1. 4 1
      exa.rs
  2. 4 4
      file.rs
  3. 32 14
      unix.rs

+ 4 - 1
exa.rs

@@ -7,6 +7,7 @@ use std::os;
 use file::File;
 use dir::Dir;
 use options::Options;
+use unix::Unix;
 
 pub mod colours;
 pub mod column;
@@ -61,8 +62,10 @@ fn exa(options: &Options, string: String) {
     // width of each column based on the length of the results and
     // padding the fields during output.
 
+    let mut cache = Unix::empty_cache();
+
     let table: Vec<Vec<String>> = files.iter()
-        .map(|f| options.columns.iter().map(|c| f.display(c)).collect())
+        .map(|f| options.columns.iter().map(|c| f.display(c, &mut cache)).collect())
         .collect();
 
     // Each column needs to have its invisible colour-formatting

+ 4 - 4
file.rs

@@ -4,7 +4,7 @@ use std::io;
 
 use column::{Column, Permissions, FileName, FileSize, User, Group};
 use format::{format_metric_bytes, format_IEC_bytes};
-use unix::{get_user_name, get_group_name};
+use unix::Unix;
 use sort::SortPart;
 use dir::Dir;
 use filetype::HasType;
@@ -89,7 +89,7 @@ impl<'a> File<'a> {
         }
     }
     
-    pub fn display(&self, column: &Column) -> String {
+    pub fn display(&self, column: &Column, unix: &mut Unix) -> String {
         match *column {
             Permissions => self.permissions_string(),
             FileName => self.file_name(),
@@ -99,10 +99,10 @@ impl<'a> File<'a> {
             // usually means it was deleted but its files weren't.
             User(uid) => {
                 let style = if uid == self.stat.unstable.uid { Yellow.bold() } else { Plain };
-                let string = get_user_name(self.stat.unstable.uid as i32).unwrap_or(self.stat.unstable.uid.to_str());
+                let string = unix.get_user_name(self.stat.unstable.uid as i32).unwrap_or(self.stat.unstable.uid.to_str());
                 return style.paint(string.as_slice());
             },
-            Group => get_group_name(self.stat.unstable.gid as u32).unwrap_or(self.stat.unstable.gid.to_str()),
+            Group => unix.get_group_name(self.stat.unstable.gid as u32).unwrap_or(self.stat.unstable.gid.to_str()),
         }
     }
     

+ 32 - 14
unix.rs

@@ -1,5 +1,6 @@
 use std::str::raw::from_c_str;
 use std::ptr::read;
+use std::collections::hashmap::HashMap;
 
 mod c {
     #![allow(non_camel_case_types)]
@@ -34,24 +35,41 @@ mod c {
         pub fn getuid() -> libc::c_int;
     }
 }
+pub struct Unix {
+    user_names:  HashMap<i32, Option<String>>,
+    group_names: HashMap<u32, Option<String>>,
+}
 
-pub fn get_user_name(uid: i32) -> Option<String> {
-    let pw = unsafe { c::getpwuid(uid) };
-    if pw.is_not_null() {
-        return unsafe { Some(from_c_str(read(pw).pw_name)) };
-    }
-    else {
-        return None;
+impl Unix {
+    pub fn empty_cache() -> Unix {
+        Unix {
+            user_names:  HashMap::new(),
+            group_names: HashMap::new(),
+        }
     }
-}
 
-pub fn get_group_name(gid: u32) -> Option<String> {
-    let gr = unsafe { c::getgrgid(gid) };
-    if gr.is_not_null() {
-        return unsafe { Some(from_c_str(read(gr).gr_name)) };
+    pub fn get_user_name<'a> (&'a mut self, uid: i32) -> Option<String> {
+        self.user_names.find_or_insert_with(uid, |&u| {
+            let pw = unsafe { c::getpwuid(u) };
+            if pw.is_not_null() {
+                return unsafe { Some(from_c_str(read(pw).pw_name)) };
+            }
+            else {
+                return None;
+            }
+        }).clone()
     }
-    else {
-        return None;
+
+    pub fn get_group_name<'a>(&'a mut self, gid: u32) -> Option<String> {
+        self.group_names.find_or_insert_with(gid, |&gid| {
+            let gr = unsafe { c::getgrgid(gid) };
+            if gr.is_not_null() {
+                return unsafe { Some(from_c_str(read(gr).gr_name)) };
+            }
+            else {
+                return None;
+            }
+        }).clone()
     }
 }