From 0f263fd5ed81dacf493c84d3fb1c130e956ed736 Mon Sep 17 00:00:00 2001 From: Avril Date: Mon, 15 Feb 2021 15:03:23 +0000 Subject: [PATCH] redo graph --- src/data/graph.rs | 307 ++++++++++++++++++++++++++-------------------- src/main.rs | 9 +- 2 files changed, 179 insertions(+), 137 deletions(-) diff --git a/src/data/graph.rs b/src/data/graph.rs index 2aead7c..c15d5c9 100644 --- a/src/data/graph.rs +++ b/src/data/graph.rs @@ -1,79 +1,7 @@ use super::*; use std::collections::HashMap; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::borrow::Borrow; -use std::iter::FusedIterator; -use std::cell::RefCell; - -#[derive(Debug, Clone, PartialEq, Eq)] -/// A reference to an INode within a graph. -pub struct INodeRef<'a>(&'a INodeInfoGraph, INode); - -impl<'a> AsRef for INodeRef<'a> -{ - fn as_ref(&self) -> &Path - { - self.0.paths_reverse.get(&self.1).unwrap() - } -} - -impl<'a> Borrow for INodeRef<'a> -{ - fn borrow(&self) -> &INode - { - &self.1 - } -} - - -impl<'a> INodeRef<'a> -{ - /// The owning graph of this INode reference. - #[inline] pub fn graph(&self) -> &INodeInfoGraph - { - self.0 - } - - /// The `FsInfo` for this INode - #[inline] pub fn info(&self) -> &FsInfo - { - self.0.inodes.get(&self.1).unwrap() - } - - /// Compute the total size of this INode. - /// - /// If this is a file, it is O(1). Otherwise, recursively compute the sizes of all children. - #[inline] pub fn size(&self) -> u64 - { - self.0.lookup_size_or(&self.1, move || { - match self.info() - { - FsInfo::File(sz, _) => *sz, - FsInfo::Directory(_) => { - self.children().map(|x| x.size()).sum() - }, - } - }) - } - - /// The internal INode - #[inline] pub fn inode(&self) -> INode - { - self.1 - } - - /// The path this INode refers to - #[inline] pub fn path(&self) -> &Path - { - self.as_ref() - } - - /// Get an iterator over the children of this INode, if it has children. - #[inline] pub fn children(&self) -> Children<'a> - { - self.0.children_of(&self.1) - } -} /// Contains a graph of all paths and inodes that were successfully stat'd #[derive(Debug, Clone, PartialEq, Eq)] @@ -85,43 +13,16 @@ pub struct INodeInfoGraph paths_reverse: HashMap, // reverse lookup of INode to PathBuf, children: HashMap>, //reverse lookup for directory INodes and their parent INodes - - total_sizes_cached: RefCell>, // the total sizes of all INodes } impl INodeInfoGraph { - fn lookup_insert_size(&self, node: INode, with: F) -> u64 - where F: FnOnce() -> u64 - { - let w = with(); - - if let Ok(mut cache) = self.total_sizes_cached.try_borrow_mut() - { - cache.insert(node, w); - w - } else { - w - } - } - fn lookup_size_or(&self, node: impl Borrow, or: F) -> u64 - where F: FnOnce() -> u64 - { - if let Ok(cache) = self.total_sizes_cached.try_borrow() { - let node = node.borrow(); - if let Some(sz) = cache.get(node) { - return *sz; - } - } - self.lookup_insert_size(*node.borrow(), or) - } /// Create a new graph from these linked `HashMap`s #[inline] pub fn new(inodes: HashMap, paths: HashMap) -> Self { Self { children: HashMap::with_capacity(inodes.len()), paths_reverse: HashMap::with_capacity(paths.len()), - total_sizes_cached: RefCell::new(HashMap::with_capacity(inodes.len())), inodes, paths, } @@ -153,58 +54,194 @@ impl INodeInfoGraph self.inodes.get(node.borrow()) } /// An iterator over top-level children of this node - pub fn children_of(&self, node: impl Borrow) -> Children<'_> + pub fn children_of(&self, node: impl Borrow) -> !//Children<'_> { - Children(self, match self.children.get(node.borrow()) { - Some(slc) => slc.iter(), - _ => [].iter(), - }) + todo!(); + /*Children(self, match self.children.get(node.borrow()) { + Some(slc) => slc.iter(), + _ => [].iter(), + })*/ } /// An iterator over all the directories in this - pub fn directories(&self) -> Directories<'_> + pub fn directories(&self) -> !//Directories<'_> { - Directories(self, self.children.keys()) + todo!()//Directories(self, self.children.keys()) } -} - -/// An iterator over all directories in a graph -#[derive(Debug, Clone)] -pub struct Directories<'a>(&'a INodeInfoGraph, std::collections::hash_map::Keys<'a, INode, Vec>); -impl<'a> Iterator for Directories<'a> -{ - type Item = INodeRef<'a>; - #[inline] fn next(&mut self) -> Option + /// Convert into a hierarchical representation + pub fn into_hierarchical(self) -> HierarchicalINodeGraph { - self.1.next().map(|x| INodeRef(self.0, *x)) + HierarchicalINodeGraph::create(self) } - #[inline] fn size_hint(&self) -> (usize, Option) { - self.1.size_hint() + + /// Convert into a hierarchical representation + pub fn create_hierarchical(&self) -> HierarchicalINodeGraph + { + HierarchicalINodeGraph::create_from(self) } } -impl<'a> ExactSizeIterator for Directories<'a>{} -impl<'a> FusedIterator for Directories<'a>{} -/// The immediate children of a specific INode -#[derive(Debug, Clone)] -pub struct Children<'a>(&'a INodeInfoGraph, std::slice::Iter<'a, INode>); +#[derive(Debug, Clone, PartialEq, Eq)] +enum NodeKind +{ + Directory(Vec, Option), + File(u64), +} -impl<'a> Iterator for Children<'a> +#[derive(Debug, Clone, PartialEq, Eq)] +struct HierarchicalNode +{ + kind: NodeKind, + inode: INode, +} + +/// A hierarchical graph of node sizes +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct HierarchicalINodeGraph { - type Item = INodeRef<'a>; - #[inline] fn next(&mut self) -> Option + table: HashMap +} + +impl HierarchicalINodeGraph +{ + /// Compute the sizes of directories in the graph + pub fn compute_recursive_sizes(&mut self) { - self.1.next().map(|x| INodeRef(self.0, *x)) + fn compute_for_dir(this: &HashMap, children: &Vec) -> u64 + { + let mut total = 0; + for child in children.iter() + { + let chl = if let Some(ch) = this.get(child) + { + match ch { + HierarchicalNode { kind: NodeKind::Directory(_, Some(sz)), .. } => { + total += sz; + continue; + }, + HierarchicalNode { kind: NodeKind::Directory(children, _), .. } => { + children + }, + HierarchicalNode { kind: NodeKind::File(sz), .. } => { + total += sz; + continue; + }, + } + } else { + continue; + }; + total += compute_for_dir(this, chl); + } + total + } + let mut length_proxy = HashMap::with_capacity(self.table.len()); + + for (path, hnode) in self.table.iter() + { + let (children, len) = match hnode { + HierarchicalNode { kind: NodeKind::Directory(children, len), .. } => { + (children, len) + }, + _ => continue, + }; + match len { + Some(sz) => length_proxy.insert(path.clone(), *sz), + None => length_proxy.insert(path.clone(), compute_for_dir(&self.table, children)), + }; + } + + for (pathref, sz) in length_proxy.into_iter() + { + self.table.get_mut(&pathref).map(|hnode| { + match hnode { + HierarchicalNode { kind: NodeKind::Directory(_, ss), .. } => { + *ss = Some(sz); + }, + _ => (), + } + }); + } } - fn size_hint(&self) -> (usize, Option) { - self.1.size_hint() + fn create_from(graph: &INodeInfoGraph) -> Self + { + let mut new = Self { + table: HashMap::with_capacity(graph.inodes.len()), + }; + + for (path, &inode) in graph.paths.iter() + { + //Lookup the INode in graph inode table + if let Some(fsinfo) = graph.inodes.get(&inode) + { + match fsinfo { + FsInfo::File(sz, parent) => { + new.table.insert(path.clone(), HierarchicalNode { + kind: NodeKind::File(*sz), + inode, + }); + }, + FsInfo::Directory(parent) => { + new.table.insert(path.clone(), HierarchicalNode { + kind: NodeKind::Directory(graph.children.get(&inode).unwrap().iter().map(|node| { + graph.paths_reverse.get(node).unwrap().clone() + }).collect(), None), + inode, + }); + }, + } + } + } + + new + } + fn create(graph: INodeInfoGraph) -> Self + { + let mut new = Self { + table: HashMap::with_capacity(graph.inodes.len()), + }; + + macro_rules! unwrap { + ($expr:expr) => { + match $expr { + Some(ex) => ex, + _ => continue, + } + }; + } + + for (path, &inode) in graph.paths.iter() + { + let path = path.clone(); + //Lookup the INode in graph inode table + if let Some(fsinfo) = graph.inodes.get(&inode) + { + match fsinfo { + FsInfo::File(sz, _) => { + new.table.insert(path, HierarchicalNode { + kind: NodeKind::File(*sz), + inode, + }); + }, + FsInfo::Directory(_) => { + new.table.insert(path, HierarchicalNode { + kind: NodeKind::Directory(unwrap!(graph.children.get(&inode)).iter().map(|node| { + graph.paths_reverse.get(node).unwrap().clone() + }).collect(), None), + inode, + }); + }, + } + } + } + + new } } -impl<'a> ExactSizeIterator for Children<'a>{} -impl<'a> FusedIterator for Children<'a>{} -impl<'a> DoubleEndedIterator for Children<'a> + +impl From for HierarchicalINodeGraph { - #[inline] fn next_back(&mut self) -> Option { - self.1.next_back().map(|x| INodeRef(self.0, *x)) + fn from(from: INodeInfoGraph) -> Self + { + Self::create(from) } } diff --git a/src/main.rs b/src/main.rs index 0f08217..5d8b472 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,8 +48,13 @@ async fn main() -> eyre::Result<()> { .with_suggestion(|| "Try running `--help`")?); let graph = work::work_on_all(state).await; - let max_size = graph.directories().map(|x| x.size()).max(); - println!("Max size: {:?}", max_size); + let mut graph = graph.into_hierarchical(); + graph.compute_recursive_sizes(); + + println!("{:?}", graph); +/* let max_size = graph.directories().map(|x| x.size()).max(); + println!("Max size: {:?}", max_size);*/ + //println!("{:?}", graph); Ok(())