diff --git a/fireflies/src/main/java/com/salesforce/apollo/fireflies/View.java b/fireflies/src/main/java/com/salesforce/apollo/fireflies/View.java index 825e5442b..ab8abcf5d 100644 --- a/fireflies/src/main/java/com/salesforce/apollo/fireflies/View.java +++ b/fireflies/src/main/java/com/salesforce/apollo/fireflies/View.java @@ -352,15 +352,21 @@ void finalizeViewChange() { log.info("Finalizing view change: {} required: {} observers: {} for: {} on: {}", context.getId(), majority, viewManagement.observers.stream().toList(), currentView(), node.getId()); HashMultiset ballots = HashMultiset.create(); - observations.values().forEach(vc -> { - final var leaving = new ArrayList<>( - vc.getChange().getLeavesList().stream().map(Digest::from).collect(Collectors.toSet())); - final var joining = new ArrayList<>( - vc.getChange().getJoinsList().stream().map(Digest::from).collect(Collectors.toSet())); - leaving.sort(Ordering.natural()); - joining.sort(Ordering.natural()); - ballots.add(new Ballot(Digest.from(vc.getChange().getCurrent()), leaving, joining, digestAlgo)); - }); + final var current = currentView(); + observations.values() + .stream() + .filter(vc -> current.equals(Digest.from(vc.getChange().getCurrent()))) + .forEach(vc -> { + final var leaving = new ArrayList<>( + vc.getChange().getLeavesList().stream().map(Digest::from).collect(Collectors.toSet())); + final var joining = new ArrayList<>( + vc.getChange().getJoinsList().stream().map(Digest::from).collect(Collectors.toSet())); + leaving.sort(Ordering.natural()); + joining.sort(Ordering.natural()); + ballots.add( + new Ballot(Digest.from(vc.getChange().getCurrent()), leaving, joining, digestAlgo)); + }); + observations.clear(); var max = ballots.entrySet() .stream() .max(Ordering.natural().onResultOf(Multiset.Entry::getCount)) @@ -369,14 +375,12 @@ void finalizeViewChange() { log.info("View consensus successful: {} required: {} cardinality: {} for: {} on: {}", max, majority, viewManagement.cardinality(), currentView(), node.getId()); viewManagement.install(max.getElement()); - observations.clear(); } else { @SuppressWarnings("unchecked") final var reversed = Comparator.comparing(e -> ((Entry) e).getCount()).reversed(); log.info("View consensus failed: {}, required: {} cardinality: {} ballots: {} for: {} on: {}", observations.size(), majority, viewManagement.cardinality(), - ballots.entrySet().stream().sorted(reversed).limit(1).toList(), currentView(), node.getId()); - observations.clear(); + ballots.entrySet().stream().sorted(reversed).toList(), currentView(), node.getId()); } scheduleViewChange(); diff --git a/fireflies/src/main/java/com/salesforce/apollo/fireflies/ViewManagement.java b/fireflies/src/main/java/com/salesforce/apollo/fireflies/ViewManagement.java index e65d036d1..3c6556fe0 100644 --- a/fireflies/src/main/java/com/salesforce/apollo/fireflies/ViewManagement.java +++ b/fireflies/src/main/java/com/salesforce/apollo/fireflies/ViewManagement.java @@ -7,7 +7,6 @@ package com.salesforce.apollo.fireflies; import com.codahale.metrics.Timer; -import com.google.common.base.Objects; import com.salesforce.apollo.bloomFilters.BloomFilter; import com.salesforce.apollo.context.DynamicContext; import com.salesforce.apollo.cryptography.Digest; @@ -578,20 +577,14 @@ private void setDiadem(final HexBloom hex) { record Ballot(Digest view, List leaving, List joining, int hash) { Ballot(Digest view, List leaving, List joining, DigestAlgorithm algo) { - this(view, leaving, joining, view.xor(joining.stream().reduce(Digest::xor).orElse(algo.getOrigin())) - .xor(leaving.stream() - .reduce(Digest::xor) - .orElse(algo.getOrigin()) - .xor( - joining.stream().reduce(Digest::xor).orElse(algo.getOrigin()))) - .hashCode()); + this(view, leaving, joining, Objects.hash(view, joining, leaving)); } @Override public boolean equals(Object obj) { if (obj instanceof Ballot b) { - return Objects.equal(view, b.view) && Objects.equal(leaving, b.leaving) && Objects.equal(joining, - b.joining); + return Objects.equals(view, b.view) && Objects.equals(leaving, b.leaving) && Objects.equals(joining, + b.joining); } return false; } @@ -603,7 +596,7 @@ public int hashCode() { @Override public String toString() { - return String.format("{h: %s, j: %s, l: %s}", hash, joining.size(), leaving.size()); + return String.format("{v: %s, h: %s, j: %s, l: %s}", view, hash, joining.size(), leaving.size()); } } } diff --git a/thoth/src/main/java/com/salesforce/apollo/thoth/KerlDHT.java b/thoth/src/main/java/com/salesforce/apollo/thoth/KerlDHT.java index 155d381b1..d26b94557 100644 --- a/thoth/src/main/java/com/salesforce/apollo/thoth/KerlDHT.java +++ b/thoth/src/main/java/com/salesforce/apollo/thoth/KerlDHT.java @@ -59,6 +59,7 @@ import org.h2.jdbcx.JdbcConnectionPool; import org.jooq.DSLContext; import org.jooq.SQLDialect; +import org.jooq.exception.DataAccessException; import org.jooq.impl.DSL; import org.joou.ULong; import org.slf4j.Logger; @@ -946,6 +947,8 @@ private void updateLocationHash(Identifier identifier) { log.error("Cannot update location hash for: {} on: {}", identifier, member.getId()); throw new IllegalStateException( "Cannot update location hash S for: %s on: %s".formatted(identifier, member.getId())); + } catch (DataAccessException e) { + log.trace("Duplicate location hash for: {} on: {}", identifier, member.getId()); } }