fix(perf): fixed a crash when cating large files and bounded memory usage

This commit is contained in:
Brooks J Rady 2021-04-13 20:57:53 +01:00
parent ee70927611
commit 265d039456
2 changed files with 26 additions and 17 deletions

View file

@ -1,9 +1,11 @@
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::VecDeque,
fmt::{self, Debug, Formatter}, fmt::{self, Debug, Formatter},
}; };
static TABSTOP_WIDTH: usize = 8; // TODO: is this always right? const TABSTOP_WIDTH: usize = 8; // TODO: is this always right?
const SCROLL_BACK: usize = 10_000;
use crate::panes::terminal_character::{ use crate::panes::terminal_character::{
CharacterStyles, TerminalCharacter, EMPTY_TERMINAL_CHARACTER, CharacterStyles, TerminalCharacter, EMPTY_TERMINAL_CHARACTER,
@ -26,7 +28,7 @@ fn get_top_non_canonical_rows(rows: &mut Vec<Row>) -> Vec<Row> {
} }
} }
fn get_bottom_canonical_row_and_wraps(rows: &mut Vec<Row>) -> Vec<Row> { fn get_bottom_canonical_row_and_wraps(rows: &mut VecDeque<Row>) -> Vec<Row> {
let mut index_of_last_non_canonical_row = None; let mut index_of_last_non_canonical_row = None;
for (i, row) in rows.iter().enumerate().rev() { for (i, row) in rows.iter().enumerate().rev() {
index_of_last_non_canonical_row = Some(i); index_of_last_non_canonical_row = Some(i);
@ -43,7 +45,7 @@ fn get_bottom_canonical_row_and_wraps(rows: &mut Vec<Row>) -> Vec<Row> {
} }
fn transfer_rows_down( fn transfer_rows_down(
source: &mut Vec<Row>, source: &mut VecDeque<Row>,
destination: &mut Vec<Row>, destination: &mut Vec<Row>,
count: usize, count: usize,
max_src_width: Option<usize>, max_src_width: Option<usize>,
@ -56,7 +58,7 @@ fn transfer_rows_down(
break; break;
} }
if next_lines.is_empty() { if next_lines.is_empty() {
match source.pop() { match source.pop_back() {
Some(next_line) => { Some(next_line) => {
let mut top_non_canonical_rows_in_dst = get_top_non_canonical_rows(destination); let mut top_non_canonical_rows_in_dst = get_top_non_canonical_rows(destination);
lines_added_to_destination -= top_non_canonical_rows_in_dst.len() as isize; lines_added_to_destination -= top_non_canonical_rows_in_dst.len() as isize;
@ -82,13 +84,13 @@ fn transfer_rows_down(
if !next_lines.is_empty() { if !next_lines.is_empty() {
match max_src_width { match max_src_width {
Some(max_row_width) => { Some(max_row_width) => {
let mut excess_rows = let excess_rows =
Row::from_rows(next_lines).split_to_rows_of_length(max_row_width); Row::from_rows(next_lines).split_to_rows_of_length(max_row_width);
source.append(&mut excess_rows); source.extend(excess_rows);
} }
None => { None => {
let excess_row = Row::from_rows(next_lines); let excess_row = Row::from_rows(next_lines);
source.push(excess_row); bounded_push(source, excess_row);
} }
} }
} }
@ -96,7 +98,7 @@ fn transfer_rows_down(
fn transfer_rows_up( fn transfer_rows_up(
source: &mut Vec<Row>, source: &mut Vec<Row>,
destination: &mut Vec<Row>, destination: &mut VecDeque<Row>,
count: usize, count: usize,
max_src_width: Option<usize>, max_src_width: Option<usize>,
max_dst_width: Option<usize>, max_dst_width: Option<usize>,
@ -122,7 +124,7 @@ fn transfer_rows_up(
break; // no more rows break; // no more rows
} }
} }
destination.push(next_lines.remove(0)); bounded_push(destination, next_lines.remove(0));
} }
if !next_lines.is_empty() { if !next_lines.is_empty() {
match max_src_width { match max_src_width {
@ -140,9 +142,16 @@ fn transfer_rows_up(
} }
} }
fn bounded_push(vec: &mut VecDeque<Row>, value: Row) {
if vec.len() >= SCROLL_BACK {
vec.pop_front();
}
vec.push_back(value)
}
#[derive(Clone)] #[derive(Clone)]
pub struct Grid { pub struct Grid {
lines_above: Vec<Row>, lines_above: VecDeque<Row>,
viewport: Vec<Row>, viewport: Vec<Row>,
lines_below: Vec<Row>, lines_below: Vec<Row>,
cursor: Cursor, cursor: Cursor,
@ -167,7 +176,7 @@ impl Debug for Grid {
impl Grid { impl Grid {
pub fn new(rows: usize, columns: usize) -> Self { pub fn new(rows: usize, columns: usize) -> Self {
Grid { Grid {
lines_above: vec![], lines_above: VecDeque::with_capacity(SCROLL_BACK),
viewport: vec![Row::new().canonical()], viewport: vec![Row::new().canonical()],
lines_below: vec![], lines_below: vec![],
cursor: Cursor::new(0, 0), cursor: Cursor::new(0, 0),
@ -235,7 +244,7 @@ impl Grid {
if !self.lines_above.is_empty() && self.viewport.len() == self.height { if !self.lines_above.is_empty() && self.viewport.len() == self.height {
let line_to_push_down = self.viewport.pop().unwrap(); let line_to_push_down = self.viewport.pop().unwrap();
self.lines_below.insert(0, line_to_push_down); self.lines_below.insert(0, line_to_push_down);
let line_to_insert_at_viewport_top = self.lines_above.pop().unwrap(); let line_to_insert_at_viewport_top = self.lines_above.pop_back().unwrap();
self.viewport.insert(0, line_to_insert_at_viewport_top); self.viewport.insert(0, line_to_insert_at_viewport_top);
} }
} }
@ -243,11 +252,11 @@ impl Grid {
if !self.lines_below.is_empty() && self.viewport.len() == self.height { if !self.lines_below.is_empty() && self.viewport.len() == self.height {
let mut line_to_push_up = self.viewport.remove(0); let mut line_to_push_up = self.viewport.remove(0);
if line_to_push_up.is_canonical { if line_to_push_up.is_canonical {
self.lines_above.push(line_to_push_up); bounded_push(&mut self.lines_above, line_to_push_up);
} else { } else {
let mut last_line_above = self.lines_above.pop().unwrap(); let mut last_line_above = self.lines_above.pop_back().unwrap();
last_line_above.append(&mut line_to_push_up.columns); last_line_above.append(&mut line_to_push_up.columns);
self.lines_above.push(last_line_above); bounded_push(&mut self.lines_above, last_line_above);
} }
let line_to_insert_at_viewport_bottom = self.lines_below.remove(0); let line_to_insert_at_viewport_bottom = self.lines_below.remove(0);
self.viewport.push(line_to_insert_at_viewport_bottom); self.viewport.push(line_to_insert_at_viewport_bottom);
@ -263,7 +272,7 @@ impl Grid {
&& viewport_canonical_lines.is_empty() && viewport_canonical_lines.is_empty()
&& !self.lines_above.is_empty() && !self.lines_above.is_empty()
{ {
let mut first_line_above = self.lines_above.pop().unwrap(); let mut first_line_above = self.lines_above.pop_back().unwrap();
first_line_above.append(&mut row.columns); first_line_above.append(&mut row.columns);
viewport_canonical_lines.push(first_line_above); viewport_canonical_lines.push(first_line_above);
cursor_canonical_line_index += 1; cursor_canonical_line_index += 1;

View file

@ -43,7 +43,7 @@ impl Stream for ReadFromPid {
// indicates end of file // indicates end of file
Poll::Ready(None) Poll::Ready(None)
} else { } else {
let res = Some(read_buffer[..=*res].to_vec()); let res = Some(read_buffer[..*res].to_vec());
Poll::Ready(res) Poll::Ready(res)
} }
} }