Querying and progress changes
parent
651d2ec542
commit
0a4c759188
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
52
src/utils.rs
52
src/utils.rs
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue