linked lists
This commit is contained in:
parent
8eab2502c7
commit
430c62c120
12 changed files with 783 additions and 544 deletions
|
|
@ -4,18 +4,17 @@ use std::{
|
|||
io::{self, BufRead, BufReader},
|
||||
mem,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
rc::Rc,
|
||||
sync::{
|
||||
OnceLock,
|
||||
mpsc::{Receiver, sync_channel},
|
||||
mpsc::{Receiver, channel},
|
||||
},
|
||||
thread,
|
||||
};
|
||||
|
||||
use crate::tui::{
|
||||
model::{LogEntry, RawLogEntry},
|
||||
processing::{FilterList, LogStream},
|
||||
};
|
||||
use dumpster::sync::Gc;
|
||||
|
||||
use crate::tui::model::{ChildInfo, LogEntry, RawLogEntry};
|
||||
|
||||
struct LogFileEntryGenerator {
|
||||
file: BufReader<File>,
|
||||
|
|
@ -45,38 +44,61 @@ impl LogFileEntryGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
fn next_entry(&mut self) -> Option<Arc<LogEntry>> {
|
||||
let mut stack = Vec::<(RawLogEntry, Vec<Arc<LogEntry>>)>::new();
|
||||
let mut curr = Vec::<Arc<LogEntry>>::new();
|
||||
fn next_entry(&mut self, prev: Option<Gc<LogEntry>>) -> Option<Gc<LogEntry>> {
|
||||
let mut stack = Vec::<(RawLogEntry, Option<Gc<LogEntry>>, Option<Gc<LogEntry>>)>::new();
|
||||
let mut curr_first = None;
|
||||
let mut curr_last = prev;
|
||||
|
||||
loop {
|
||||
let entry = self.next_raw_entry()?;
|
||||
|
||||
let new_entry = Arc::new(match entry.fields.message() {
|
||||
let new_entry = Gc::new(match entry.fields.message() {
|
||||
Some("enter") => {
|
||||
stack.push((entry, mem::take(&mut curr)));
|
||||
stack.push((entry, curr_first.take(), curr_last.take()));
|
||||
continue;
|
||||
}
|
||||
Some("exit") => {
|
||||
// TODO: does it match?
|
||||
let Some((enter, prev)) = stack.pop() else {
|
||||
let Some((enter, prev_first, prev_last)) = stack.pop() else {
|
||||
panic!("exit before entry");
|
||||
};
|
||||
let sub_entries = mem::replace(&mut curr, prev);
|
||||
let first_child = mem::replace(&mut curr_first, prev_first);
|
||||
let last_child = mem::replace(&mut curr_last, prev_last);
|
||||
|
||||
let prev = curr_last.clone();
|
||||
let next = OnceLock::new();
|
||||
|
||||
LogEntry::Sub {
|
||||
enter: enter,
|
||||
sub_entries,
|
||||
enter,
|
||||
exit: entry,
|
||||
count_sub: OnceLock::new(),
|
||||
children: Gc::new(ChildInfo {
|
||||
first_child,
|
||||
last_child,
|
||||
prev,
|
||||
next,
|
||||
}),
|
||||
}
|
||||
}
|
||||
_ => LogEntry::Single { raw: entry },
|
||||
_ => {
|
||||
let prev = curr_last.clone();
|
||||
let next = OnceLock::new();
|
||||
|
||||
LogEntry::Single { entry, prev, next }
|
||||
}
|
||||
});
|
||||
|
||||
if stack.is_empty() {
|
||||
return Some(new_entry);
|
||||
} else if let Some(last) = &mut curr_last {
|
||||
last.initialize_next().get_or_init({
|
||||
let new_entry = new_entry.clone();
|
||||
move || new_entry
|
||||
});
|
||||
*last = new_entry;
|
||||
} else {
|
||||
curr.push(new_entry);
|
||||
assert!(curr_first.is_none());
|
||||
curr_first = Some(new_entry.clone());
|
||||
curr_last = Some(new_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -85,30 +107,38 @@ impl LogFileEntryGenerator {
|
|||
struct Inner {
|
||||
pub path: PathBuf,
|
||||
|
||||
entry_generator: Receiver<Arc<LogEntry>>,
|
||||
cached_entries: Vec<Arc<LogEntry>>,
|
||||
first: Option<Gc<LogEntry>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LogfileReader(Arc<RefCell<Inner>>);
|
||||
pub struct LogfileReader(Rc<RefCell<Inner>>);
|
||||
|
||||
impl LogfileReader {
|
||||
pub fn new(p: &Path) -> io::Result<Self> {
|
||||
let (tx, rx) = sync_channel(1000);
|
||||
let file = File::open(p)?;
|
||||
|
||||
let mut generator = LogFileEntryGenerator {
|
||||
file: BufReader::new(File::open(p)?),
|
||||
file: BufReader::new(file),
|
||||
};
|
||||
|
||||
thread::spawn(move || {
|
||||
while let Some(i) = generator.next_entry() {
|
||||
tx.send(i).unwrap();
|
||||
}
|
||||
});
|
||||
let first = generator.next_entry(None);
|
||||
|
||||
Ok(Self(Arc::new(RefCell::new(Inner {
|
||||
if let Some(mut curr_last) = first.clone() {
|
||||
thread::spawn(move || {
|
||||
while let Some(new) = generator.next_entry(Some(curr_last.clone())) {
|
||||
assert!(new.prev().is_some());
|
||||
curr_last.initialize_next().get_or_init({
|
||||
let new = new.clone();
|
||||
|| new
|
||||
});
|
||||
curr_last = new;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok(Self(Rc::new(RefCell::new(Inner {
|
||||
path: p.to_path_buf(),
|
||||
cached_entries: Vec::new(),
|
||||
entry_generator: rx,
|
||||
first,
|
||||
}))))
|
||||
}
|
||||
|
||||
|
|
@ -116,55 +146,7 @@ impl LogfileReader {
|
|||
self.0.borrow().path.clone()
|
||||
}
|
||||
|
||||
fn fill_buf_to_access_index(&mut self, n: usize) -> Option<Arc<LogEntry>> {
|
||||
while self.0.borrow().cached_entries.len() <= n {
|
||||
let entry = self.0.borrow().entry_generator.recv().ok()?;
|
||||
self.0.borrow_mut().cached_entries.push(entry);
|
||||
}
|
||||
|
||||
Some(Arc::clone(&self.0.borrow().cached_entries[n]))
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> LogFileReaderStream {
|
||||
LogFileReaderStream {
|
||||
reader: self.clone(),
|
||||
curr: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LogFileReaderStream {
|
||||
reader: LogfileReader,
|
||||
curr: usize,
|
||||
}
|
||||
|
||||
impl LogStream for LogFileReaderStream {
|
||||
fn next(&mut self, _fl: &FilterList) -> Option<(Arc<LogEntry>, usize)> {
|
||||
let entry = self.reader.fill_buf_to_access_index(self.curr)?;
|
||||
self.curr += 1;
|
||||
|
||||
Some((entry, 0))
|
||||
}
|
||||
|
||||
fn prev(&mut self, _fl: &FilterList) -> Option<(Arc<LogEntry>, usize)> {
|
||||
if self.curr == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let entry = self.reader.fill_buf_to_access_index(self.curr)?;
|
||||
self.curr -= 1;
|
||||
|
||||
Some((entry, 0))
|
||||
}
|
||||
|
||||
fn clone(&self) -> Box<dyn LogStream> {
|
||||
Box::new(Self {
|
||||
reader: self.reader.clone(),
|
||||
curr: self.curr,
|
||||
})
|
||||
}
|
||||
|
||||
fn enclosing_log_entry(&self) -> Option<(Arc<LogEntry>, usize)> {
|
||||
None
|
||||
pub fn first(&self) -> Option<Gc<LogEntry>> {
|
||||
self.0.borrow().first.clone()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue