mirror of
https://code.blicky.net/yorhel/ncdu.git
synced 2026-01-12 17:08:39 -09:00
Keep track of uncounted hard links to speed up refresh+delete operations
This commit is contained in:
parent
ba14c0938f
commit
5929bf57cc
1 changed files with 29 additions and 5 deletions
|
|
@ -134,7 +134,7 @@ pub const Entry = packed struct {
|
||||||
l.next = d.key_ptr.*.next;
|
l.next = d.key_ptr.*.next;
|
||||||
d.key_ptr.*.next = l;
|
d.key_ptr.*.next = l;
|
||||||
}
|
}
|
||||||
|
inodes.addUncounted(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
var it: ?*Dir = parent;
|
var it: ?*Dir = parent;
|
||||||
|
|
@ -173,10 +173,12 @@ pub const Entry = packed struct {
|
||||||
d.value_ptr.nlink = 0;
|
d.value_ptr.nlink = 0;
|
||||||
if (l.next == l) {
|
if (l.next == l) {
|
||||||
_ = inodes.map.remove(l);
|
_ = inodes.map.remove(l);
|
||||||
|
_ = inodes.uncounted.remove(l);
|
||||||
inodes.total_blocks = saturateSub(inodes.total_blocks, self.blocks);
|
inodes.total_blocks = saturateSub(inodes.total_blocks, self.blocks);
|
||||||
} else {
|
} else {
|
||||||
if (d.key_ptr.* == l)
|
if (d.key_ptr.* == l)
|
||||||
d.key_ptr.* = l.next;
|
d.key_ptr.* = l.next;
|
||||||
|
inodes.addUncounted(l.next);
|
||||||
// This is O(n), which in this context has the potential to
|
// This is O(n), which in this context has the potential to
|
||||||
// slow ncdu down to a crawl. But this function is only called
|
// slow ncdu down to a crawl. But this function is only called
|
||||||
// on refresh/delete operations and even then it's not common
|
// on refresh/delete operations and even then it's not common
|
||||||
|
|
@ -343,6 +345,13 @@ pub const inodes = struct {
|
||||||
// the hard links are not counted as part of the parent directories yet.
|
// the hard links are not counted as part of the parent directories yet.
|
||||||
pub var total_blocks: Blocks = 0;
|
pub var total_blocks: Blocks = 0;
|
||||||
|
|
||||||
|
// List of nodes in 'map' with !counted, to speed up addAllStats().
|
||||||
|
// If this list grows large relative to the number of nodes in 'map', then
|
||||||
|
// this list is cleared and uncounted_full is set instead, so that
|
||||||
|
// addAllStats() will do a full iteration over 'map'.
|
||||||
|
var uncounted = std.HashMap(*Link, void, HashContext, 80).init(main.allocator);
|
||||||
|
var uncounted_full = true; // start with true for the initial scan
|
||||||
|
|
||||||
const Inode = packed struct {
|
const Inode = packed struct {
|
||||||
// Whether this Inode is counted towards the parent directories.
|
// Whether this Inode is counted towards the parent directories.
|
||||||
counted: bool,
|
counted: bool,
|
||||||
|
|
@ -367,6 +376,15 @@ pub const inodes = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn addUncounted(l: *Link) void {
|
||||||
|
if (uncounted_full) return;
|
||||||
|
if (uncounted.count() > map.count()/8) {
|
||||||
|
uncounted.clearAndFree();
|
||||||
|
uncounted_full = true;
|
||||||
|
} else
|
||||||
|
(uncounted.getOrPut(l) catch unreachable).key_ptr.* = l;
|
||||||
|
}
|
||||||
|
|
||||||
// Add/remove this inode from the parent Dir sizes. When removing stats,
|
// Add/remove this inode from the parent Dir sizes. When removing stats,
|
||||||
// the list of *Links and their sizes and counts must be in the exact same
|
// the list of *Links and their sizes and counts must be in the exact same
|
||||||
// state as when the stats were added. Hence, any modification to the Link
|
// state as when the stats were added. Hence, any modification to the Link
|
||||||
|
|
@ -419,11 +437,17 @@ pub const inodes = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: A version that doesn't have to iterate over the entire map, for
|
|
||||||
// smaller refresh/delete updates.
|
|
||||||
pub fn addAllStats() void {
|
pub fn addAllStats() void {
|
||||||
var it = map.iterator();
|
if (uncounted_full) {
|
||||||
while (it.next()) |e| setStats(e, true);
|
var it = map.iterator();
|
||||||
|
while (it.next()) |e| setStats(e, true);
|
||||||
|
} else {
|
||||||
|
var it = uncounted.iterator();
|
||||||
|
while (it.next()) |u| if (map.getEntry(u.key_ptr.*)) |e| setStats(e, true);
|
||||||
|
}
|
||||||
|
uncounted_full = false;
|
||||||
|
if (uncounted.count() > 0)
|
||||||
|
uncounted.clearAndFree();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue