##// END OF EJS Templates
rust: bump to memmap2 0.5.3, micro-timer 0.4.0, and crossbeam-channel 0.5.0...
rust: bump to memmap2 0.5.3, micro-timer 0.4.0, and crossbeam-channel 0.5.0 The merge in 12adf8c695ed had conflicts in rust/Cargo.lock and rust/hg-core/Cargo.toml . Let's ignore rust/Cargo.lock - it is regenerated. For rust/hg-core/Cargo.toml, stable had dd6b67d5c256 "rust: fix unsound `OwningDirstateMap`" which introduced ouroboros (and dropped stable_deref_trait). Default had ec8d9b5a5e7c "rust-hg-core: upgrade dependencies" which had a lot of churn bumping minimum versions - also patch versions. It is indeed a good idea to bump to *allow* use of latest package. That means that major versions should be bumped for packages after 1.0, and for packages below 1.0 minor versions should be bumped too. But it doesn't work to try enforce a policy of using latest patch by bumping versions at arbitrary times. For good or bad, the merge doesn't seem to have resolved the conflicts correctly, and many of the minor "upgrade dependencies" were lost again. Unfortunately, it also lost the bump of memmap2 to 0.5.3, which is needed for Fedora packaging where 0.4 isn't available. Same with micro-timer bump to 0.4 (which already is used in rhg). crossbeam-channel bump was also lost. This change fixes that regression by redoing these "important" lines of the merge "correctly". I propose this for stable, even though dependency changes on stable branches are annoying.

File last commit:

r48767:e834b79d default
r50312:1bad05cf stable
Show More
main.rs
146 lines | 4.6 KiB | application/rls-services+xml | RustLexer
// Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net>
//
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2 or any later version.
use clap::*;
use hg::revlog::node::*;
use hg::revlog::nodemap::*;
use hg::revlog::*;
use memmap2::MmapOptions;
use rand::Rng;
use std::fs::File;
use std::io;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::time::Instant;
mod index;
use index::Index;
fn mmap_index(repo_path: &Path) -> Index {
let mut path = PathBuf::from(repo_path);
path.extend([".hg", "store", "00changelog.i"].iter());
Index::load_mmap(path)
}
fn mmap_nodemap(path: &Path) -> NodeTree {
let file = File::open(path).unwrap();
let mmap = unsafe { MmapOptions::new().map(&file).unwrap() };
let len = mmap.len();
NodeTree::load_bytes(Box::new(mmap), len)
}
/// Scan the whole index and create the corresponding nodemap file at `path`
fn create(index: &Index, path: &Path) -> io::Result<()> {
let mut file = File::create(path)?;
let start = Instant::now();
let mut nm = NodeTree::default();
for rev in 0..index.len() {
let rev = rev as Revision;
nm.insert(index, index.node(rev).unwrap(), rev).unwrap();
}
eprintln!("Nodemap constructed in RAM in {:?}", start.elapsed());
file.write(&nm.into_readonly_and_added_bytes().1)?;
eprintln!("Nodemap written to disk");
Ok(())
}
fn query(index: &Index, nm: &NodeTree, prefix: &str) {
let start = Instant::now();
let res = NodePrefix::from_hex(prefix).map(|p| nm.find_bin(index, p));
println!("Result found in {:?}: {:?}", start.elapsed(), res);
}
fn bench(index: &Index, nm: &NodeTree, queries: usize) {
let len = index.len() as u32;
let mut rng = rand::thread_rng();
let nodes: Vec<Node> = (0..queries)
.map(|_| {
index
.node((rng.gen::<u32>() % len) as Revision)
.unwrap()
.clone()
})
.collect();
if queries < 10 {
let nodes_hex: Vec<String> =
nodes.iter().map(|n| format!("{:x}", n)).collect();
println!("Nodes: {:?}", nodes_hex);
}
let mut last: Option<Revision> = None;
let start = Instant::now();
for node in nodes.iter() {
last = nm.find_bin(index, node.into()).unwrap();
}
let elapsed = start.elapsed();
println!(
"Did {} queries in {:?} (mean {:?}), last was {:x} with result {:?}",
queries,
elapsed,
elapsed / (queries as u32),
nodes.last().unwrap(),
last
);
}
fn main() {
let matches = App::new("Nodemap pure Rust example")
.arg(
Arg::with_name("REPOSITORY")
.help("Path to the repository, always necessary for its index")
.required(true),
)
.arg(
Arg::with_name("NODEMAP_FILE")
.help("Path to the nodemap file, independent of REPOSITORY")
.required(true),
)
.subcommand(
SubCommand::with_name("create")
.about("Create NODEMAP_FILE by scanning repository index"),
)
.subcommand(
SubCommand::with_name("query")
.about("Query NODEMAP_FILE for PREFIX")
.arg(Arg::with_name("PREFIX").required(true)),
)
.subcommand(
SubCommand::with_name("bench")
.about(
"Perform #QUERIES random successful queries on NODEMAP_FILE")
.arg(Arg::with_name("QUERIES").required(true)),
)
.get_matches();
let repo = matches.value_of("REPOSITORY").unwrap();
let nm_path = matches.value_of("NODEMAP_FILE").unwrap();
let index = mmap_index(&Path::new(repo));
if let Some(_) = matches.subcommand_matches("create") {
println!("Creating nodemap file {} for repository {}", nm_path, repo);
create(&index, &Path::new(nm_path)).unwrap();
return;
}
let nm = mmap_nodemap(&Path::new(nm_path));
if let Some(matches) = matches.subcommand_matches("query") {
let prefix = matches.value_of("PREFIX").unwrap();
println!(
"Querying {} in nodemap file {} of repository {}",
prefix, nm_path, repo
);
query(&index, &nm, prefix);
}
if let Some(matches) = matches.subcommand_matches("bench") {
let queries =
usize::from_str(matches.value_of("QUERIES").unwrap()).unwrap();
println!(
"Doing {} random queries in nodemap file {} of repository {}",
queries, nm_path, repo
);
bench(&index, &nm, queries);
}
}