Skip to content

Commit ca4a303

Browse files
authored
Move names into a pre-created name pool (#1056)
### What does this PR do? All File names are now present in a pre-defined pool that is stored in State. Each Directory node continues to hold its own name.
1 parent dfbb553 commit ca4a303

File tree

2 files changed

+67
-28
lines changed

2 files changed

+67
-28
lines changed

lading/src/bin/logrotate_fs.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -239,12 +239,16 @@ impl Filesystem for LogrotateFS {
239239

240240
// reaming children
241241
if let Some(child_inodes) = self.state.readdir(ino as usize) {
242-
for (child_name, child_ino) in child_inodes {
242+
for child_ino in child_inodes {
243243
let file_type = self
244244
.state
245245
.get_file_type(*child_ino)
246246
.expect("inode must have file type");
247-
entries.push((*child_ino as u64, file_type, child_name.clone()));
247+
let child_name = self
248+
.state
249+
.get_name(*child_ino)
250+
.expect("inode must have a name");
251+
entries.push((*child_ino as u64, file_type, child_name.to_string()));
248252
}
249253
} else {
250254
reply.error(ENOENT);

lading/src/generator/file_gen/model.rs

+61-26
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
//use lading_payload::block;
44

5-
use std::collections::HashMap;
5+
use std::collections::{HashMap, HashSet};
66

77
use bytes::Bytes;
88
use lading_payload::block;
@@ -52,6 +52,10 @@ pub struct File {
5252
/// The ordinal number of this File. If the file is foo.log the ordinal
5353
/// number is 0, if foo.log.1 then 1 etc.
5454
ordinal: u8,
55+
56+
/// The group ID of this File. So for instance all File instances that are
57+
/// called foo.log, foo.log.1 etc have the same group ID.
58+
group_id: u8,
5559
}
5660

5761
impl File {
@@ -131,7 +135,7 @@ impl File {
131135
/// instances or `File` instances. Root directory will not have a `parent`.
132136
#[derive(Debug)]
133137
pub struct Directory {
134-
children: HashMap<String, Inode>,
138+
children: HashSet<Inode>,
135139
parent: Option<Inode>,
136140
}
137141

@@ -140,8 +144,6 @@ pub struct Directory {
140144
pub enum Node {
141145
/// A [`File`]
142146
File {
143-
/// The name of this file. If the full path is /logs/foo.log then this is "foo.log".
144-
name: String,
145147
/// The `File` instance.
146148
file: File,
147149
},
@@ -176,6 +178,8 @@ pub struct State {
176178
now: Tick,
177179
block_cache: block::Cache,
178180
max_bytes_per_file: u64,
181+
// [GroupID, [Names]]. The interior Vec have size `max_rotations`.
182+
group_names: Vec<Vec<String>>,
179183
}
180184

181185
/// The attributes of a `Node`.
@@ -220,10 +224,10 @@ impl State {
220224
let mut nodes = HashMap::new();
221225

222226
let mut root_dir = Directory {
223-
children: HashMap::new(),
227+
children: HashSet::new(),
224228
parent: None,
225229
};
226-
root_dir.children.insert("logs".to_string(), logs_inode);
230+
root_dir.children.insert(logs_inode);
227231
nodes.insert(
228232
root_inode,
229233
Node::Directory {
@@ -233,12 +237,10 @@ impl State {
233237
);
234238

235239
let mut logs_dir = Directory {
236-
children: HashMap::new(),
240+
children: HashSet::new(),
237241
parent: Some(root_inode),
238242
};
239-
logs_dir
240-
.children
241-
.insert("foo.log".to_string(), foo_log_inode);
243+
logs_dir.children.insert(foo_log_inode);
242244
nodes.insert(
243245
logs_inode,
244246
Node::Directory {
@@ -247,6 +249,17 @@ impl State {
247249
},
248250
);
249251

252+
let mut group_names = Vec::new();
253+
254+
// Create names for the rotation group
255+
let base_name = "foo.log".to_string();
256+
let mut names = Vec::new();
257+
names.push(base_name.clone()); // Ordinal 0
258+
for i in 1..=max_rotations {
259+
names.push(format!("foo.log.{i}")); // Ordinal i
260+
}
261+
group_names.push(names);
262+
250263
let foo_log = File {
251264
parent: logs_inode,
252265

@@ -261,14 +274,9 @@ impl State {
261274

262275
read_only: false,
263276
ordinal: 0,
277+
group_id: 0,
264278
};
265-
nodes.insert(
266-
foo_log_inode,
267-
Node::File {
268-
name: "foo.log".to_string(),
269-
file: foo_log,
270-
},
271-
);
279+
nodes.insert(foo_log_inode, Node::File { file: foo_log });
272280

273281
// NOTE this structure is going to be a problem when I include rotating
274282
// files. Specifically the inodes will need to change so there might
@@ -281,6 +289,7 @@ impl State {
281289
now: 0,
282290
block_cache,
283291
max_bytes_per_file,
292+
group_names,
284293
}
285294
}
286295

@@ -344,10 +353,21 @@ impl State {
344353
self.advance_time(now);
345354

346355
if let Some(Node::Directory { dir, .. }) = self.nodes.get(&parent_inode) {
347-
dir.children.get(name).copied()
348-
} else {
349-
None
356+
for &child_inode in &dir.children {
357+
if let Some(node) = self.nodes.get(&child_inode) {
358+
let child_name = match node {
359+
Node::File { file } => {
360+
&self.group_names[file.group_id as usize][file.ordinal as usize]
361+
}
362+
Node::Directory { name, .. } => name,
363+
};
364+
if child_name == name {
365+
return Some(child_inode);
366+
}
367+
}
368+
}
350369
}
370+
None
351371
}
352372

353373
/// Look up the attributes for an `Inode`.
@@ -388,10 +408,7 @@ impl State {
388408
self.advance_time(now);
389409

390410
match self.nodes.get_mut(&inode) {
391-
Some(Node::File {
392-
name: _,
393-
ref mut file,
394-
}) => {
411+
Some(Node::File { ref mut file }) => {
395412
let bytes_written = usize::try_from(file.bytes_written)
396413
.expect("more bytes written than machine word");
397414

@@ -421,7 +438,7 @@ impl State {
421438
///
422439
/// Function does not advance time in the model.
423440
#[tracing::instrument(skip(self))]
424-
pub fn readdir(&self, inode: Inode) -> Option<&HashMap<String, Inode>> {
441+
pub fn readdir(&self, inode: Inode) -> Option<&HashSet<Inode>> {
425442
if let Some(Node::Directory { dir, .. }) = self.nodes.get(&inode) {
426443
Some(&dir.children)
427444
} else {
@@ -438,6 +455,24 @@ impl State {
438455
})
439456
}
440457

458+
/// Return the name of the inode if it exists
459+
#[tracing::instrument(skip(self))]
460+
pub fn get_name(&self, inode: Inode) -> Option<&str> {
461+
if inode == self.root_inode {
462+
Some("/")
463+
} else {
464+
self.nodes
465+
.get(&inode)
466+
.map(|node| match node {
467+
Node::Directory { name, .. } => name,
468+
Node::File { file } => {
469+
&self.group_names[file.group_id as usize][file.ordinal as usize]
470+
}
471+
})
472+
.map(String::as_str)
473+
}
474+
}
475+
441476
/// Return the parent inode of an inode, if it exists
442477
#[tracing::instrument(skip(self))]
443478
pub fn get_parent_inode(&self, inode: Inode) -> Option<Inode> {
@@ -464,7 +499,7 @@ impl State {
464499
let subdirectory_count = dir
465500
.children
466501
.iter()
467-
.filter(|(_, child_inode)| {
502+
.filter(|child_inode| {
468503
matches!(self.nodes.get(child_inode), Some(Node::Directory { .. }))
469504
})
470505
.count();

0 commit comments

Comments
 (0)