Skip to content

Commit e511e15

Browse files
committed
Auto merge of #5619 - Eh2406:remove_redundant_hashmap, r=alexcrichton
Remove redundant hashmap We have two structures keeping track of parshall lists of `conflicting_prev_active`. I believe that they are always merged with each other before being used. (CI will tell me if I am wrong.) So in this PR we us pass a `&mut` so that it is merged as it gos. This saves us a clone/allocation of a hashmap for every tick, although most of the time one or both are empty so I doubt it will be a big performance change. Keeping the comments clear in this code is very important. @alexcrichton, are there new comments that should go in with this change or more that should come out?
2 parents 90b5df8 + d6d5758 commit e511e15

File tree

3 files changed

+27
-47
lines changed

3 files changed

+27
-47
lines changed

src/cargo/core/interning.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use serde::{Serialize, Serializer};
22

33
use std::fmt;
4-
use std::sync::RwLock;
4+
use std::sync::Mutex;
55
use std::collections::HashSet;
66
use std::str;
77
use std::ptr;
@@ -14,8 +14,8 @@ pub fn leak(s: String) -> &'static str {
1414
}
1515

1616
lazy_static! {
17-
static ref STRING_CACHE: RwLock<HashSet<&'static str>> =
18-
RwLock::new(HashSet::new());
17+
static ref STRING_CACHE: Mutex<HashSet<&'static str>> =
18+
Mutex::new(HashSet::new());
1919
}
2020

2121
#[derive(Clone, Copy)]
@@ -33,7 +33,7 @@ impl Eq for InternedString {}
3333

3434
impl InternedString {
3535
pub fn new(str: &str) -> InternedString {
36-
let mut cache = STRING_CACHE.write().unwrap();
36+
let mut cache = STRING_CACHE.lock().unwrap();
3737
let s = cache.get(str).map(|&s| s).unwrap_or_else(|| {
3838
let s = leak(str.to_string());
3939
cache.insert(s);

src/cargo/core/resolver/mod.rs

Lines changed: 22 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ use std::time::{Duration, Instant};
5454

5555
use semver;
5656

57-
use core::{Dependency, PackageId, Registry, Summary};
58-
use core::PackageIdSpec;
5957
use core::interning::InternedString;
58+
use core::PackageIdSpec;
59+
use core::{Dependency, PackageId, Registry, Summary};
6060
use util::config::Config;
6161
use util::errors::{CargoError, CargoResult};
6262
use util::profile;
@@ -70,9 +70,9 @@ pub use self::encode::{Metadata, WorkspaceResolve};
7070
pub use self::resolve::{Deps, DepsNotReplaced, Resolve};
7171
pub use self::types::Method;
7272

73+
mod conflict_cache;
7374
mod context;
7475
mod encode;
75-
mod conflict_cache;
7676
mod resolve;
7777
mod types;
7878

@@ -293,9 +293,9 @@ fn activate_deps_loop(
293293
let mut backtracked = false;
294294

295295
loop {
296-
let next = remaining_candidates.next(&cx, &dep);
296+
let next = remaining_candidates.next(&mut conflicting_activations, &cx, &dep);
297297

298-
let (candidate, has_another) = next.or_else(|conflicting| {
298+
let (candidate, has_another) = next.ok_or(()).or_else(|_| {
299299
// If we get here then our `remaining_candidates` was just
300300
// exhausted, so `dep` failed to activate.
301301
//
@@ -304,10 +304,6 @@ fn activate_deps_loop(
304304
// candidates whatsoever then it's time to bail entirely.
305305
trace!("{}[{}]>{} -- no candidates", parent.name(), cur, dep.name());
306306

307-
// Add all the reasons to our frame's list of conflicting
308-
// activations, as we may use this to start backtracking later.
309-
conflicting_activations.extend(conflicting);
310-
311307
// Use our list of `conflicting_activations` to add to our
312308
// global list of past conflicting activations, effectively
313309
// globally poisoning `dep` if `conflicting_activations` ever
@@ -402,13 +398,7 @@ fn activate_deps_loop(
402398
dep.name(),
403399
candidate.summary.version()
404400
);
405-
let res = activate(
406-
&mut cx,
407-
registry,
408-
Some((&parent, &dep)),
409-
candidate,
410-
&method,
411-
);
401+
let res = activate(&mut cx, registry, Some((&parent, &dep)), candidate, &method);
412402

413403
let successfully_activated = match res {
414404
// Success! We've now activated our `candidate` in our context
@@ -522,8 +512,6 @@ fn activate_deps_loop(
522512
// we'll want to present an error message for sure.
523513
let activate_for_error_message = has_past_conflicting_dep && !has_another && {
524514
just_here_for_the_error_messages || {
525-
conflicting_activations
526-
.extend(remaining_candidates.conflicting_prev_active.clone());
527515
find_candidate(
528516
&mut backtrack_stack.clone(),
529517
&parent,
@@ -692,13 +680,10 @@ struct BacktrackFrame {
692680
/// is defined within a `Context`.
693681
///
694682
/// Candidates passed to `new` may not be returned from `next` as they could be
695-
/// filtered out, and if iteration stops a map of all packages which caused
696-
/// filtered out candidates to be filtered out will be returned.
683+
/// filtered out, and as they are filtered the causes will be added to `conflicting_prev_active`.
697684
#[derive(Clone)]
698685
struct RemainingCandidates {
699686
remaining: RcVecIter<Candidate>,
700-
// note: change to RcList or something if clone is to expensive
701-
conflicting_prev_active: HashMap<PackageId, ConflictReason>,
702687
// This is a inlined peekable generator
703688
has_another: Option<Candidate>,
704689
}
@@ -707,7 +692,6 @@ impl RemainingCandidates {
707692
fn new(candidates: &Rc<Vec<Candidate>>) -> RemainingCandidates {
708693
RemainingCandidates {
709694
remaining: RcVecIter::new(Rc::clone(candidates)),
710-
conflicting_prev_active: HashMap::new(),
711695
has_another: None,
712696
}
713697
}
@@ -730,9 +714,10 @@ impl RemainingCandidates {
730714
/// original list for the reason listed.
731715
fn next(
732716
&mut self,
717+
conflicting_prev_active: &mut HashMap<PackageId, ConflictReason>,
733718
cx: &Context,
734719
dep: &Dependency,
735-
) -> Result<(Candidate, bool), HashMap<PackageId, ConflictReason>> {
720+
) -> Option<(Candidate, bool)> {
736721
let prev_active = cx.prev_active(dep);
737722

738723
for (_, b) in self.remaining.by_ref() {
@@ -743,9 +728,9 @@ impl RemainingCandidates {
743728
if let Some(link) = b.summary.links() {
744729
if let Some(a) = cx.links.get(&link) {
745730
if a != b.summary.package_id() {
746-
self.conflicting_prev_active
731+
conflicting_prev_active
747732
.entry(a.clone())
748-
.or_insert_with(|| ConflictReason::Links(link.to_string()));
733+
.or_insert(ConflictReason::Links(link));
749734
continue;
750735
}
751736
}
@@ -764,7 +749,7 @@ impl RemainingCandidates {
764749
.find(|a| compatible(a.version(), b.summary.version()))
765750
{
766751
if *a != b.summary {
767-
self.conflicting_prev_active
752+
conflicting_prev_active
768753
.entry(a.package_id().clone())
769754
.or_insert(ConflictReason::Semver);
770755
continue;
@@ -777,21 +762,14 @@ impl RemainingCandidates {
777762
// get returned later, and if we replaced something then that was
778763
// actually the candidate to try first so we return that.
779764
if let Some(r) = mem::replace(&mut self.has_another, Some(b)) {
780-
return Ok((r, true));
765+
return Some((r, true));
781766
}
782767
}
783768

784769
// Alright we've entirely exhausted our list of candidates. If we've got
785770
// something stashed away return that here (also indicating that there's
786-
// nothing else). If nothing is stashed away we return the list of all
787-
// conflicting activations, if any.
788-
//
789-
// TODO: can the `conflicting_prev_active` clone be avoided here? should
790-
// panic if this is called twice and an error is already returned
791-
self.has_another
792-
.take()
793-
.map(|r| (r, false))
794-
.ok_or_else(|| self.conflicting_prev_active.clone())
771+
// nothing else).
772+
self.has_another.take().map(|r| (r, false))
795773
}
796774
}
797775

@@ -831,12 +809,14 @@ fn find_candidate(
831809
conflicting_activations: &HashMap<PackageId, ConflictReason>,
832810
) -> Option<(Candidate, bool, BacktrackFrame)> {
833811
while let Some(mut frame) = backtrack_stack.pop() {
834-
let next = frame
835-
.remaining_candidates
836-
.next(&frame.context_backup, &frame.dep);
812+
let next = frame.remaining_candidates.next(
813+
&mut frame.conflicting_activations,
814+
&frame.context_backup,
815+
&frame.dep,
816+
);
837817
let (candidate, has_another) = match next {
838-
Ok(pair) => pair,
839-
Err(_) => continue,
818+
Some(pair) => pair,
819+
None => continue,
840820
};
841821
// When we're calling this method we know that `parent` failed to
842822
// activate. That means that some dependency failed to get resolved for

src/cargo/core/resolver/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ pub enum ConflictReason {
279279
/// The `links` key is being violated. For example one crate in the
280280
/// dependency graph has `links = "foo"` but this crate also had that, and
281281
/// we're only allowed one per dependency graph.
282-
Links(String),
282+
Links(InternedString),
283283

284284
/// A dependency listed features that weren't actually available on the
285285
/// candidate. For example we tried to activate feature `foo` but the

0 commit comments

Comments
 (0)