Querying and progress changes

master
random-geek 2021-01-26 14:32:58 -08:00
parent 651d2ec542
commit 0a4c759188
15 changed files with 108 additions and 73 deletions

View File

@ -184,49 +184,52 @@ fn parse_cmd_line_args() -> anyhow::Result<InstArgs> {
}
fn print_progress(done: usize, total: usize, real_start: Instant,
eta_start: Instant)
fn print_editing_status(done: usize, total: usize, real_start: Instant,
eta_start: Instant, show_progress: bool)
{
let progress = match total {
0 => 0.0,
_ => done as f32 / total as f32
};
let now = Instant::now();
let real_elapsed = now.duration_since(real_start);
let eta_elapsed = now.duration_since(eta_start);
let remaining = if progress >= 0.1 {
Some(Duration::from_secs_f32(
eta_elapsed.as_secs_f32() / progress * (1.0 - progress)
))
} else {
None
};
if show_progress {
let eta_elapsed = now.duration_since(eta_start);
let progress = match total {
0 => 0.,
_ => done as f32 / total as f32
};
const TOTAL_BARS: usize = 25;
let num_bars = (progress * TOTAL_BARS as f32) as usize;
let bars = "=".repeat(num_bars);
eprint!(
"\r[{bars:<total_bars$}] {progress:.1}% | {elapsed} elapsed \
| {remaining} remaining",
bars=bars,
total_bars=TOTAL_BARS,
progress=progress * 100.0,
elapsed=fmt_duration(real_elapsed),
remaining=if let Some(d) = remaining {
fmt_duration(d)
let remaining = if progress >= 0.1 {
Some(Duration::from_secs_f32(
eta_elapsed.as_secs_f32() / progress * (1. - progress)
))
} else {
String::from("--:--")
}
);
None
};
const TOTAL_BARS: usize = 25;
let num_bars = (progress * TOTAL_BARS as f32) as usize;
let bars = "=".repeat(num_bars);
eprint!(
"\r[{bars:<total_bars$}] {progress:.1}% | {elapsed} elapsed \
| {remaining} remaining",
bars=bars,
total_bars=TOTAL_BARS,
progress=progress * 100.,
elapsed=fmt_duration(real_elapsed),
remaining=if let Some(d) = remaining {
fmt_duration(d)
} else {
String::from("--:--")
}
);
} else {
eprint!("\rProcessing... {} elapsed", fmt_duration(real_elapsed));
}
std::io::stdout().flush().unwrap();
}
#[inline]
fn print_log(log_type: LogType, msg: String) {
eprintln!("{}: {}", log_type, msg)
}
@ -246,7 +249,7 @@ pub fn run_cmd_line() {
let (handle, status) = spawn_compute_thread(args);
const TICK: Duration = Duration::from_millis(25);
const UPDATE_INTERVAL: Duration = Duration::from_millis(250);
const UPDATE_INTERVAL: Duration = Duration::from_millis(500);
let mut last_update = Instant::now();
let mut querying_start = last_update;
@ -311,8 +314,8 @@ pub fn run_cmd_line() {
{
let s = status.get();
// TODO: Update duration format? e.g. 1m 42s remaining
print_progress(s.blocks_done, s.blocks_total,
querying_start, editing_start);
print_editing_status(s.blocks_done, s.blocks_total,
querying_start, editing_start, s.show_progress);
last_update = now;
need_newline = true;
}

View File

@ -17,7 +17,7 @@ fn clone(inst: &mut InstBundle) {
let offset = inst.args.offset.unwrap();
let dst_area = src_area + offset;
let mut keys = query_keys(&mut inst.db, &inst.status,
None, Some(dst_area), false, true);
Vec::new(), Some(dst_area), false, true);
// Sort blocks according to offset such that we don't read blocks that
// have already been written.

View File

@ -5,7 +5,7 @@ use crate::utils::query_keys;
fn delete_blocks(inst: &mut InstBundle) {
let keys = query_keys(&mut inst.db, &inst.status, None,
let keys = query_keys(&mut inst.db, &inst.status, Vec::new(),
inst.args.area, inst.args.invert, false);
inst.status.begin_editing();

View File

@ -11,7 +11,7 @@ fn delete_metadata(inst: &mut InstBundle) {
let node = inst.args.node.as_ref().map(|s| s.as_bytes().to_owned());
let keys = query_keys(&mut inst.db, &mut inst.status,
node.as_deref(), inst.args.area, inst.args.invert, true);
node.iter().collect(), inst.args.area, inst.args.invert, true);
inst.status.begin_editing();
let mut count: u64 = 0;

View File

@ -66,7 +66,7 @@ fn delete_objects(inst: &mut InstBundle) {
.map(|s| TwoWaySearcher::new(s));
let keys = query_keys(&mut inst.db, &mut inst.status,
search_obj.as_deref(), inst.args.area, inst.args.invert, true);
search_obj.iter().collect(), inst.args.area, inst.args.invert, true);
inst.status.begin_editing();
let mut count: u64 = 0;

View File

@ -11,7 +11,7 @@ fn delete_timers(inst: &mut InstBundle) {
let node = inst.args.node.as_ref().map(|s| s.as_bytes().to_owned());
let keys = query_keys(&mut inst.db, &mut inst.status,
node.as_deref(), inst.args.area, inst.args.invert, true);
node.iter().collect(), inst.args.area, inst.args.invert, true);
inst.status.begin_editing();
let mut count: u64 = 0;

View File

@ -26,7 +26,7 @@ fn fill(inst: &mut InstBundle) {
let node = inst.args.new_node.as_ref().unwrap().as_bytes().to_owned();
let keys = query_keys(&mut inst.db, &mut inst.status,
None, Some(area), false, true);
Vec::new(), Some(area), false, true);
inst.status.begin_editing();

View File

@ -30,8 +30,8 @@ fn overlay_no_offset(inst: &mut InstBundle) {
let invert = inst.args.invert;
// Get keys from input database.
let keys = query_keys(&mut idb, &inst.status, None,
inst.args.area, invert, true);
let keys = query_keys(&mut idb, &inst.status,
Vec::new(), inst.args.area, invert, true);
inst.status.begin_editing();
for key in keys {
@ -106,8 +106,8 @@ fn overlay_with_offset(inst: &mut InstBundle) {
let idb = inst.idb.as_mut().unwrap();
// Get keys from output database.
let keys = query_keys(&mut inst.db, &inst.status, None,
dst_area, inst.args.invert, true);
let keys = query_keys(&mut inst.db, &inst.status,
Vec::new(), dst_area, inst.args.invert, true);
inst.status.begin_editing();
for key in keys {

View File

@ -59,7 +59,7 @@ fn replace_in_inv(inst: &mut InstBundle) {
let node = inst.args.node.as_ref().map(|s| s.as_bytes().to_owned());
let keys = query_keys(&mut inst.db, &mut inst.status,
node.as_deref(), inst.args.area, inst.args.invert, true);
node.iter().collect(), inst.args.area, inst.args.invert, true);
inst.status.begin_editing();
let mut item_mods: u64 = 0;

View File

@ -113,10 +113,10 @@ fn do_replace(
fn replace_nodes(inst: &mut InstBundle) {
let node = inst.args.node.as_ref().unwrap().as_bytes();
let new_node = inst.args.new_node.as_ref().unwrap().as_bytes();
let node = inst.args.node.as_ref().unwrap().as_bytes().to_owned();
let new_node = inst.args.new_node.as_ref().unwrap().as_bytes().to_owned();
let keys = query_keys(&mut inst.db, &inst.status,
Some(node), inst.args.area, inst.args.invert, true);
vec![&node], inst.args.area, inst.args.invert, true);
inst.status.begin_editing();
let mut count = 0;

View File

@ -13,7 +13,7 @@ fn set_meta_var(inst: &mut InstBundle) {
let node = inst.args.node.as_ref().map(|s| s.as_bytes().to_owned());
let keys = query_keys(&mut inst.db, &mut inst.status,
node.as_deref(), inst.args.area, inst.args.invert, true);
node.iter().collect(), inst.args.area, inst.args.invert, true);
inst.status.begin_editing();
let mut count: u64 = 0;

View File

@ -46,7 +46,7 @@ fn set_param2(inst: &mut InstBundle) {
let node = inst.args.node.as_ref().map(|s| s.as_bytes().to_owned());
let keys = query_keys(&mut inst.db, &mut inst.status,
node.as_deref(), inst.args.area, false, true);
node.iter().collect(), inst.args.area, false, true);
inst.status.begin_editing();

View File

@ -1,19 +1,19 @@
use super::Command;
use std::time::Instant;
use crate::instance::InstBundle;
use crate::utils::fmt_duration;
fn vacuum(inst: &mut InstBundle) {
inst.status.log_info("Starting vacuum.");
let start = Instant::now();
// TODO: Show simple timer in main thread.
match inst.db.vacuum() {
inst.status.set_show_progress(false); // No ETA for vacuum.
inst.status.begin_editing();
let res = inst.db.vacuum();
inst.status.end_editing();
match res {
Ok(_) => {
let time = fmt_duration(start.elapsed());
inst.status.log_info(format!("Completed vacuum in {}.", time));
inst.status.log_info(format!("Completed vacuum."));
},
Err(e) => inst.status.log_error(format!("Vacuum failed: {}.", e))
}
@ -24,7 +24,7 @@ pub fn get_command() -> Command {
Command {
func: vacuum,
verify_args: None,
args: vec![],
help: "Rebuild map database to reduce its size"
args: Vec::new(),
help: "Rebuild map database to reduce its size."
}
}

View File

@ -58,6 +58,7 @@ pub enum InstState {
#[derive(Clone)]
pub struct InstStatus {
pub show_progress: bool,
pub blocks_total: usize,
pub blocks_done: usize,
pub state: InstState
@ -66,6 +67,7 @@ pub struct InstStatus {
impl InstStatus {
fn new() -> Self {
Self {
show_progress: true,
blocks_total: 0,
blocks_done: 0,
state: InstState::Ignore
@ -115,6 +117,10 @@ impl StatusServer {
self.status.lock().unwrap().blocks_done += 1;
}
pub fn set_show_progress(&self, sp: bool) {
self.status.lock().unwrap().show_progress = sp;
}
pub fn begin_editing(&self) {
self.set_state(InstState::Editing);
}

View File

@ -12,7 +12,7 @@ pub fn query_keys(
db: &mut MapDatabase,
status: &StatusServer,
// TODO: Allow multiple names for setmetavar and replaceininv.
search_str: Option<&[u8]>,
search_strs: Vec<&Vec<u8>>,
area: Option<Area>,
invert: bool,
include_partial: bool
@ -21,15 +21,15 @@ pub fn query_keys(
// Prepend 16-bit search string length to reduce false positives.
// This will break if the name-ID map format changes.
let search_bytes = search_str.map(|s| {
let string16s: Vec<Vec<u8>> = search_strs.iter().map(|&s| {
let mut res = Vec::new();
res.write_u16::<BigEndian>(s.len() as u16).unwrap();
res.extend(s);
res
});
let data_searcher = search_bytes.as_ref().map(|b| {
}).collect();
let data_searchers: Vec<TwoWaySearcher> = string16s.iter().map(|b| {
TwoWaySearcher::new(b)
});
}).collect();
let mut keys = Vec::new();
// Area of included block positions.
@ -49,8 +49,9 @@ pub fn query_keys(
continue;
}
}
if let Some(s) = &data_searcher {
if s.search_in(&data).is_none() {
if !data_searchers.is_empty() {
// Data must match at least one search string.
if data_searchers.iter().any(|s| s.search_in(&data).is_some()) {
continue;
}
}
@ -91,13 +92,13 @@ pub fn fmt_duration(dur: Duration) -> String {
pub fn fmt_big_num(num: u64) -> String {
let f_num = num as f32;
let abbrevs = vec![
("T".to_string(), 1_000_000_000_000.),
("B".to_string(), 1_000_000_000.),
("M".to_string(), 1_000_000.),
("k".to_string(), 1_000.)
const ABBREVS: [(&str, f32); 4] = [
("T", 1_000_000_000_000.),
("B", 1_000_000_000.),
("M", 1_000_000.),
("k", 1_000.)
];
for (suffix, unit) in abbrevs {
for &(suffix, unit) in &ABBREVS {
if f_num >= unit {
let mantissa = f_num / unit;
let place_vals =
@ -109,3 +110,28 @@ pub fn fmt_big_num(num: u64) -> String {
}
format!("{}", f_num.round())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_nums() {
let pairs = [
(0, "0"),
(3, "3"),
(42, "42"),
(999, "999"),
(1_000, "1.00k"),
(33_870, "33.9k"),
(470_999, "471k"),
(555_678_000, "556M"),
(1_672_234_000, "1.67B"),
(77_864_672_234_000, "77.9T"),
];
for pair in &pairs {
assert_eq!(fmt_big_num(pair.0), pair.1.to_string());
}
}
}