This is an automated email from the ASF dual-hosted git repository.
benedict pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-accord.git
The following commit(s) were added to refs/heads/trunk by this push:
new 3aba47c2 Accord Fixes: - Not updating CommandsForKey in all cases on
restart Also Improve: - Tracing coverage of FetchRoute - LatestDeps.equals -
Route toString methods
3aba47c2 is described below
commit 3aba47c29a1cb13dba05814fd6b007165193fd7e
Author: Benedict Elliott Smith <[email protected]>
AuthorDate: Sat Jul 12 10:27:58 2025 +0100
Accord Fixes:
- Not updating CommandsForKey in all cases on restart
Also Improve:
- Tracing coverage of FetchRoute
- LatestDeps.equals
- Route toString methods
patch by Benedict; reviewed by Alex Petrov for CASSANDRA-20763
---
.../main/java/accord/coordinate/FetchRoute.java | 32 ++++++++++++-----
.../src/main/java/accord/coordinate/Infer.java | 21 +++++++----
.../main/java/accord/coordinate/MaybeRecover.java | 2 +-
.../src/main/java/accord/coordinate/Recover.java | 2 +-
.../accord/impl/AbstractConfigurationService.java | 4 +--
.../src/main/java/accord/impl/AbstractLoader.java | 9 ++---
.../java/accord/impl/InMemoryCommandStore.java | 3 +-
.../src/main/java/accord/local/SafeCommand.java | 2 +-
.../main/java/accord/primitives/AbstractKeys.java | 41 +++++++++++++++++++++-
.../java/accord/primitives/AbstractRanges.java | 28 ++++++++++-----
.../main/java/accord/primitives/FullKeyRoute.java | 6 ----
.../java/accord/primitives/FullRangeRoute.java | 7 ----
.../src/main/java/accord/primitives/KeyRoute.java | 9 +++++
.../main/java/accord/primitives/LatestDeps.java | 14 ++++++++
.../src/main/java/accord/primitives/Range.java | 1 -
.../main/java/accord/primitives/RangeRoute.java | 5 +++
16 files changed, 132 insertions(+), 54 deletions(-)
diff --git a/accord-core/src/main/java/accord/coordinate/FetchRoute.java
b/accord-core/src/main/java/accord/coordinate/FetchRoute.java
index b60ecffa..e7bd8daa 100644
--- a/accord-core/src/main/java/accord/coordinate/FetchRoute.java
+++ b/accord-core/src/main/java/accord/coordinate/FetchRoute.java
@@ -20,6 +20,9 @@ package accord.coordinate;
import java.util.function.BiConsumer;
+import javax.annotation.Nullable;
+
+import accord.api.Tracing;
import accord.local.Commands;
import accord.local.Node;
import accord.local.SafeCommand;
@@ -33,6 +36,7 @@ import accord.primitives.Route;
import accord.primitives.TxnId;
import accord.utils.MapReduceConsume;
+import static accord.api.TraceEventType.FETCH;
import static accord.coordinate.Infer.InvalidIf.NotKnownToBeInvalid;
import static
accord.coordinate.Infer.InvalidateAndCallback.locallyInvalidateAndCallback;
import static accord.local.CommandStores.*;
@@ -46,28 +50,31 @@ public class FetchRoute extends CheckShards<Participants<?>>
{
final LatentStoreSelector reportTo;
final BiConsumer<Route<?>, Throwable> callback;
- FetchRoute(Node node, TxnId txnId, Infer.InvalidIf invalidIf,
Participants<?> contactable, LatentStoreSelector reportTo, BiConsumer<Route<?>,
Throwable> callback)
+
+ FetchRoute(Node node, TxnId txnId, Infer.InvalidIf invalidIf,
Participants<?> contactable, LatentStoreSelector reportTo, BiConsumer<Route<?>,
Throwable> callback, @Nullable Tracing tracing)
{
- super(node, node.someSequentialExecutor(), txnId, contactable,
IncludeInfo.Route, null, invalidIf);
+ super(node, node.someSequentialExecutor(), txnId, contactable,
txnId.epoch(), IncludeInfo.Route, null, invalidIf, tracing);
this.reportTo = reportTo;
this.callback = callback;
}
- public static void fetchRoute(Node node, TxnId txnId, Infer.InvalidIf
invalidIf, Participants<?> unseekables, LatentStoreSelector reportTo,
BiConsumer<Route<?>, Throwable> callback)
+ public static void fetchRoute(Node node, TxnId txnId, Infer.InvalidIf
invalidIf, Participants<?> unseekables, LatentStoreSelector reportTo,
BiConsumer<Route<?>, Throwable> callback, Tracing tracing)
{
if (!node.topology().hasEpoch(txnId.epoch()))
{
- node.withEpochAtLeast(txnId.epoch(), null, callback, () ->
fetchRoute(node, txnId, invalidIf, unseekables, reportTo, callback));
+ if (tracing != null)
+ tracing.trace(null, "Waiting for epoch %d", txnId.epoch());
+ node.withEpochAtLeast(txnId.epoch(), null, callback, () ->
fetchRoute(node, txnId, invalidIf, unseekables, reportTo, callback, tracing));
return;
}
- FetchRoute fetchRoute = new FetchRoute(node, txnId, invalidIf,
unseekables, reportTo, callback);
+ FetchRoute fetchRoute = new FetchRoute(node, txnId, invalidIf,
unseekables, reportTo, callback, tracing);
fetchRoute.start();
}
public static void fetchRoute(Node node, TxnId txnId, Participants<?>
contactable, LatentStoreSelector reportTo, BiConsumer<Route<?>, Throwable>
callback)
{
- fetchRoute(node, txnId, NotKnownToBeInvalid, contactable, reportTo,
callback);
+ fetchRoute(node, txnId, NotKnownToBeInvalid, contactable, reportTo,
callback, node.agent().trace(txnId, FETCH));
}
@Override
@@ -88,7 +95,7 @@ public class FetchRoute extends CheckShards<Participants<?>>
Known known = Nothing;
if (merged != null)
known = merged.finish(query, query, query,
success.withQuorum, previouslyKnownToBeInvalidIf).knownFor(txnId, query, query);
- reportRouteNotFound(node, success.withQuorum, known, txnId,
query, reportTo, callback);
+ reportRouteNotFound(node, success.withQuorum, known, txnId,
query, reportTo, callback, tracing);
}
else
{
@@ -120,13 +127,16 @@ public class FetchRoute extends
CheckShards<Participants<?>>
}
}
- private static void reportRouteNotFound(Node node, WithQuorum withQuorum,
Known found, TxnId txnId, Participants<?> participants, LatentStoreSelector
reportTo, BiConsumer<Route<?>, Throwable> callback)
+ private static void reportRouteNotFound(Node node, WithQuorum withQuorum,
Known found, TxnId txnId, Participants<?> participants, LatentStoreSelector
reportTo, BiConsumer<Route<?>, Throwable> callback, @Nullable Tracing tracing)
{
switch (found.outcome())
{
default: throw new AssertionError("Unknown outcome: " +
found.outcome());
case Abort:
- locallyInvalidateAndCallback(node, txnId,
reportTo.refine(txnId, null, participants), participants, null, callback);
+ if (tracing != null)
+ tracing.trace(null, "No Route. Found %s; invalidating",
found);
+
+ locallyInvalidateAndCallback(node, txnId,
reportTo.refine(txnId, null, participants), participants, null, callback,
tracing);
break;
case Unknown:
@@ -135,6 +145,10 @@ public class FetchRoute extends
CheckShards<Participants<?>>
Invalidate.invalidate(node, txnId, participants, false,
reportTo, (outcome, throwable) -> callback.accept(null, throwable));
break;
}
+ else if (tracing != null)
+ {
+ tracing.trace(null, "No Route. Found %s; cannot invalidate
(%s, %s)", found, withQuorum, found.canProposeInvalidation());
+ }
case Erased:
case WasApply:
case Apply:
diff --git a/accord-core/src/main/java/accord/coordinate/Infer.java
b/accord-core/src/main/java/accord/coordinate/Infer.java
index e5e4c6b3..71ee91fb 100644
--- a/accord-core/src/main/java/accord/coordinate/Infer.java
+++ b/accord-core/src/main/java/accord/coordinate/Infer.java
@@ -20,6 +20,9 @@ package accord.coordinate;
import java.util.function.BiConsumer;
+import javax.annotation.Nullable;
+
+import accord.api.Tracing;
import accord.local.Command;
import accord.local.CommandStores.StoreFinder;
import accord.local.CommandStores.StoreSelector;
@@ -111,8 +114,9 @@ public class Infer
final Participants<?> participants;
final T param;
final BiConsumer<T, Throwable> callback;
+ final Tracing tracing;
- private CleanupAndCallback(Node node, TxnId txnId, StoreSelector
reportTo, Participants<?> participants, T param, BiConsumer<T, Throwable>
callback)
+ private CleanupAndCallback(Node node, TxnId txnId, StoreSelector
reportTo, Participants<?> participants, T param, BiConsumer<T, Throwable>
callback, Tracing tracing)
{
this.node = node;
this.txnId = txnId;
@@ -120,6 +124,7 @@ public class Infer
this.participants = participants;
this.param = param;
this.callback = callback;
+ this.tracing = tracing;
}
void start()
@@ -152,19 +157,19 @@ public class Infer
static class InvalidateAndCallback<T> extends CleanupAndCallback<T>
{
- private InvalidateAndCallback(Node node, TxnId txnId, StoreSelector
selector, Participants<?> participants, T param, BiConsumer<T, Throwable>
callback)
+ private InvalidateAndCallback(Node node, TxnId txnId, StoreSelector
selector, Participants<?> participants, T param, BiConsumer<T, Throwable>
callback, @Nullable Tracing tracing)
{
- super(node, txnId, selector, participants, param, callback);
+ super(node, txnId, selector, participants, param, callback,
tracing);
}
- public static <T> void locallyInvalidateAndCallback(Node node, TxnId
txnId, long lowEpoch, long highEpoch, Participants<?> participants, T param,
BiConsumer<T, Throwable> callback)
+ public static <T> void locallyInvalidateAndCallback(Node node, TxnId
txnId, long lowEpoch, long highEpoch, Participants<?> participants, T param,
BiConsumer<T, Throwable> callback, @Nullable Tracing tracing)
{
- new InvalidateAndCallback<>(node, txnId,
StoreFinder.selector(participants, lowEpoch, highEpoch), participants, param,
callback).start();
+ new InvalidateAndCallback<>(node, txnId,
StoreFinder.selector(participants, lowEpoch, highEpoch), participants, param,
callback, tracing).start();
}
- public static <T> void locallyInvalidateAndCallback(Node node, TxnId
txnId, StoreSelector selector, Participants<?> participants, T param,
BiConsumer<T, Throwable> callback)
+ public static <T> void locallyInvalidateAndCallback(Node node, TxnId
txnId, StoreSelector selector, Participants<?> participants, T param,
BiConsumer<T, Throwable> callback, @Nullable Tracing tracing)
{
- new InvalidateAndCallback<>(node, txnId, selector, participants,
param, callback).start();
+ new InvalidateAndCallback<>(node, txnId, selector, participants,
param, callback, tracing).start();
}
@Override
@@ -172,6 +177,8 @@ public class Infer
{
// we're applying an invalidation, so the record will not be
cleaned up until the whole range is truncated
Command command = safeCommand.current();
+ if (tracing != null)
+ tracing.trace(safeStore.commandStore(), "Invalidating (from
%s)", command.saveStatus());
Invariants.require(!command.hasBeen(PreCommitted) ||
command.hasBeen(Status.Truncated), "Unexpected status for %s", command);
Commands.commitInvalidate(safeStore, safeCommand, participants);
return null;
diff --git a/accord-core/src/main/java/accord/coordinate/MaybeRecover.java
b/accord-core/src/main/java/accord/coordinate/MaybeRecover.java
index 160c30c7..922c671b 100644
--- a/accord-core/src/main/java/accord/coordinate/MaybeRecover.java
+++ b/accord-core/src/main/java/accord/coordinate/MaybeRecover.java
@@ -135,7 +135,7 @@ public class MaybeRecover extends CheckShards<Route<?>>
case Abort:
commitInvalidate(node, txnId, Route.merge(full.route,
(Route) query), txnId.epoch());
- locallyInvalidateAndCallback(node, txnId, txnId.epoch(),
txnId.epoch(), someRoute, full.toProgressToken(), callback);
+ locallyInvalidateAndCallback(node, txnId, txnId.epoch(),
txnId.epoch(), someRoute, full.toProgressToken(), callback, null);
break;
}
}
diff --git a/accord-core/src/main/java/accord/coordinate/Recover.java
b/accord-core/src/main/java/accord/coordinate/Recover.java
index 20bd8cbb..398b5080 100644
--- a/accord-core/src/main/java/accord/coordinate/Recover.java
+++ b/accord-core/src/main/java/accord/coordinate/Recover.java
@@ -530,7 +530,7 @@ public class Recover implements Callback<RecoverReply>,
BiConsumer<Result, Throw
Commit.Invalidate.commitInvalidate(node, txnId, route,
invalidateUntil);
});
isDone = true;
- locallyInvalidateAndCallback(node, txnId, reportTo.refine(txnId, null,
route), route, ProgressToken.INVALIDATED, callback);
+ locallyInvalidateAndCallback(node, txnId, reportTo.refine(txnId, null,
route), route, ProgressToken.INVALIDATED, callback, null);
}
private void propose(Accept.Kind kind, Timestamp executeAt,
List<RecoverOk> recoverOkList)
diff --git
a/accord-core/src/main/java/accord/impl/AbstractConfigurationService.java
b/accord-core/src/main/java/accord/impl/AbstractConfigurationService.java
index 0c4d0e56..bf579e79 100644
--- a/accord-core/src/main/java/accord/impl/AbstractConfigurationService.java
+++ b/accord-core/src/main/java/accord/impl/AbstractConfigurationService.java
@@ -376,9 +376,9 @@ public abstract class
AbstractConfigurationService<EpochState extends AbstractCo
long lastAcked = epochs.lastAcknowledged();
if (lastAcked == 0 && lastReceived > 0)
{
- logger.debug("Epoch {} received; waiting for {} to ack before
reporting", topology.epoch(), epochs.minEpoch(), executor());
+ logger.debug("Epoch {} received; waiting for {} to ack before
reporting", topology.epoch(), epochs.minEpoch());
epochs.acknowledgeFuture(epochs.minEpoch())
- .invokeIfSuccess(() -> reportTopology(topology, isLoad,
startSync))
+ .invokeIfSuccess(() -> reportTopology(topology, isLoad,
startSync), executor())
.begin(agent);
return;
}
diff --git a/accord-core/src/main/java/accord/impl/AbstractLoader.java
b/accord-core/src/main/java/accord/impl/AbstractLoader.java
index 152f67c8..c0dba44d 100644
--- a/accord-core/src/main/java/accord/impl/AbstractLoader.java
+++ b/accord-core/src/main/java/accord/impl/AbstractLoader.java
@@ -31,23 +31,19 @@ import accord.utils.Invariants;
import static accord.primitives.SaveStatus.Applying;
import static accord.primitives.SaveStatus.PreApplied;
-import static accord.primitives.SaveStatus.TruncatedApply;
import static accord.primitives.SaveStatus.TruncatedApplyWithOutcome;
import static accord.primitives.Status.Applied;
-import static accord.primitives.Status.Stable;
-import static accord.primitives.Status.Truncated;
import static accord.primitives.Txn.Kind.Write;
public abstract class AbstractLoader implements Journal.Loader
{
- protected void maybeApplyWrites(SafeCommandStore safeStore, TxnId txnId)
+ protected void initialiseState(SafeCommandStore safeStore, TxnId txnId)
{
SafeCommand safeCommand = safeStore.unsafeGet(txnId);
Command command = safeCommand.current();
if (command.saveStatus().compareTo(SaveStatus.Stable) >= 0 &&
command.saveStatus().compareTo(PreApplied) <= 0)
{
- if (Commands.maybeExecute(safeStore, safeCommand, command, true,
true))
- return;
+ Commands.maybeExecute(safeStore, safeCommand, command, false,
true);
}
else if (command.saveStatus().compareTo(Applying) >= 0 &&
command.saveStatus().compareTo(TruncatedApplyWithOutcome) <= 0)
{
@@ -64,7 +60,6 @@ public abstract class AbstractLoader implements Journal.Loader
Commands.postApply(ss, txnId, -1, true);
}))
.begin(safeStore.agent());
- return;
}
}
else Invariants.expect(command.hasBeen(Applied));
diff --git a/accord-core/src/main/java/accord/impl/InMemoryCommandStore.java
b/accord-core/src/main/java/accord/impl/InMemoryCommandStore.java
index 08d59d83..857c98f5 100644
--- a/accord-core/src/main/java/accord/impl/InMemoryCommandStore.java
+++ b/accord-core/src/main/java/accord/impl/InMemoryCommandStore.java
@@ -90,7 +90,6 @@ import org.agrona.collections.ObjectHashSet;
import static accord.local.Cleanup.Input.FULL;
import static accord.local.KeyHistory.ASYNC;
import static accord.local.KeyHistory.NONE;
-import static accord.local.KeyHistory.SYNC;
import static accord.local.RedundantStatus.Coverage.ALL;
import static accord.local.StoreParticipants.Filter.LOAD;
import static accord.primitives.Known.KnownRoute.MaybeRoute;
@@ -1191,7 +1190,7 @@ public abstract class InMemoryCommandStore extends
CommandStore
return
AsyncChains.success(commandStore.executeInContext(commandStore,
txnId,
(SafeCommandStore safeStore) -> {
-
maybeApplyWrites(safeStore, txnId);
+
initialiseState(safeStore, txnId);
return null;
}));
}
diff --git a/accord-core/src/main/java/accord/local/SafeCommand.java
b/accord-core/src/main/java/accord/local/SafeCommand.java
index dcccb4c3..943c4483 100644
--- a/accord-core/src/main/java/accord/local/SafeCommand.java
+++ b/accord-core/src/main/java/accord/local/SafeCommand.java
@@ -67,7 +67,7 @@ public abstract class SafeCommand
public <C extends Command> C update(SafeCommandStore safeStore, C update,
boolean force)
{
Command prev = current();
- if (prev == update)
+ if (prev == update && !force)
return update;
set(update);
diff --git a/accord-core/src/main/java/accord/primitives/AbstractKeys.java
b/accord-core/src/main/java/accord/primitives/AbstractKeys.java
index 2dee5b85..74d1289d 100644
--- a/accord-core/src/main/java/accord/primitives/AbstractKeys.java
+++ b/accord-core/src/main/java/accord/primitives/AbstractKeys.java
@@ -20,6 +20,7 @@ package accord.primitives;
import java.util.Arrays;
import java.util.Iterator;
+import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
@@ -27,6 +28,8 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import javax.annotation.Nullable;
+
import accord.api.RoutingKey;
import accord.utils.ArrayBuffers.ObjectBuffers;
import accord.utils.AsymmetricComparator;
@@ -172,9 +175,45 @@ public abstract class AbstractKeys<K extends RoutableKey>
implements Iterable<K>
@Override
public String toString()
{
- return stream().map(Object::toString).collect(Collectors.joining(",",
"[", "]"));
+ return toString("", null);
}
+ protected String toString(String suffix, @Nullable Function<? super K,
String> keySuffixes)
+ {
+ if (isEmpty() && suffix.isEmpty())
+ return "[]";
+
+ StringBuilder sb = new StringBuilder();
+ sb.append('[');
+ int i = 0;
+ while (i < keys.length)
+ {
+ if (i > 0) sb.append(", ");
+ Object prefix = keys[i].prefix();
+ int j = i + 1;
+ while (j < keys.length && Objects.equals(prefix, keys[j].prefix()))
+ ++j;
+ if (prefix != null)
+ {
+ sb.append(prefix);
+ sb.append(':');
+ sb.append('[');
+ }
+ while (i < j)
+ {
+ K key = keys[i++];
+ sb.append(key.printableSuffix());
+ if (keySuffixes != null)
+ sb.append(keySuffixes.apply(key));
+ if (i < j) sb.append(',');
+ }
+ if (prefix != null)
+ sb.append(']');
+ }
+ sb.append(suffix);
+ sb.append(']');
+ return sb.toString();
+ }
// TODO (expected, efficiency): accept cached buffers
protected K[] slice(AbstractRanges ranges, IntFunction<K[]> factory)
diff --git a/accord-core/src/main/java/accord/primitives/AbstractRanges.java
b/accord-core/src/main/java/accord/primitives/AbstractRanges.java
index 266b434d..62f9e8d6 100644
--- a/accord-core/src/main/java/accord/primitives/AbstractRanges.java
+++ b/accord-core/src/main/java/accord/primitives/AbstractRanges.java
@@ -20,6 +20,7 @@ package accord.primitives;
import java.util.Arrays;
import java.util.Iterator;
+import java.util.Objects;
import java.util.function.Function;
import javax.annotation.Nonnull;
@@ -623,9 +624,13 @@ public abstract class AbstractRanges implements
Iterable<Range>, Routables<Range
@Override
public String toString()
{
- if (isEmpty()) return "[]";
- if (ranges[0].start().prefix() == null)
- return Arrays.toString(ranges);
+ return toString("");
+ }
+
+ protected String toString(String suffix)
+ {
+ if (isEmpty() && suffix.isEmpty())
+ return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
@@ -635,18 +640,23 @@ public abstract class AbstractRanges implements
Iterable<Range>, Routables<Range
if (i > 0) sb.append(", ");
Object prefix = ranges[i].start().prefix();
int j = i + 1;
- while (j < ranges.length &&
prefix.equals(ranges[j].end().prefix()))
+ while (j < ranges.length && Objects.equals(prefix,
ranges[j].end().prefix()))
++j;
- sb.append(prefix);
- sb.append(':');
- sb.append('[');
+ if (prefix != null)
+ {
+ sb.append(prefix);
+ sb.append(':');
+ sb.append('[');
+ }
while (i < j)
{
sb.append(ranges[i++].toSuffixString());
- if (i < j) sb.append(", ");
+ if (i < j) sb.append(',');
}
- sb.append(']');
+ if (prefix != null)
+ sb.append(']');
}
+ sb.append(suffix);
sb.append(']');
return sb.toString();
}
diff --git a/accord-core/src/main/java/accord/primitives/FullKeyRoute.java
b/accord-core/src/main/java/accord/primitives/FullKeyRoute.java
index 4f6396a6..a910e47a 100644
--- a/accord-core/src/main/java/accord/primitives/FullKeyRoute.java
+++ b/accord-core/src/main/java/accord/primitives/FullKeyRoute.java
@@ -70,10 +70,4 @@ public class FullKeyRoute extends KeyRoute implements
FullRoute<RoutingKey>
{
return true;
}
-
- @Override
- public String toString()
- {
- return "{homeKey:" + homeKey + ',' + super.toString() + '}';
- }
}
diff --git a/accord-core/src/main/java/accord/primitives/FullRangeRoute.java
b/accord-core/src/main/java/accord/primitives/FullRangeRoute.java
index 327f95f0..8f2d78f0 100644
--- a/accord-core/src/main/java/accord/primitives/FullRangeRoute.java
+++ b/accord-core/src/main/java/accord/primitives/FullRangeRoute.java
@@ -62,11 +62,4 @@ public class FullRangeRoute extends RangeRoute implements
FullRoute<Range>
{
return this;
}
-
- @Override
- public String toString()
- {
- return "{homeKey:" + homeKey + ',' + super.toString() + '}';
- }
-
}
diff --git a/accord-core/src/main/java/accord/primitives/KeyRoute.java
b/accord-core/src/main/java/accord/primitives/KeyRoute.java
index f2ab3e5c..a1beeccf 100644
--- a/accord-core/src/main/java/accord/primitives/KeyRoute.java
+++ b/accord-core/src/main/java/accord/primitives/KeyRoute.java
@@ -18,6 +18,8 @@
package accord.primitives;
+import java.util.Objects;
+
import accord.utils.Invariants;
import accord.api.RoutingKey;
@@ -164,4 +166,11 @@ public abstract class KeyRoute extends
AbstractUnseekableKeys implements Route<R
{
return newKeys == keys ? this : new PartialKeyRoute(homeKey, newKeys);
}
+
+ @Override
+ public String toString()
+ {
+ boolean containsHomeKey = containsHomeKey();
+ return toString(containsHomeKey ? "" : "(homeKey:" + homeKey + ')',
containsHomeKey ? test -> test.equals(homeKey) ? "*" : "" : null);
+ }
}
diff --git a/accord-core/src/main/java/accord/primitives/LatestDeps.java
b/accord-core/src/main/java/accord/primitives/LatestDeps.java
index 8f856c29..605674b3 100644
--- a/accord-core/src/main/java/accord/primitives/LatestDeps.java
+++ b/accord-core/src/main/java/accord/primitives/LatestDeps.java
@@ -20,6 +20,7 @@ package accord.primitives;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@@ -270,6 +271,19 @@ public class LatestDeps extends
ReducingRangeMap<LatestDeps.LatestEntry>
+ (localDeps == null ? "" : ",local:" +
localDeps.keyDeps.toBriefString() + "/" + localDeps.rangeDeps.toBriefString())
+ (coordinatedDeps == null ? "" : ",coordinated:" +
coordinatedDeps.keyDeps.toBriefString() + "/" +
coordinatedDeps.rangeDeps.toBriefString());
}
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof LatestEntry))
+ return false;
+
+ LatestEntry that = (LatestEntry) obj;
+ return this.known == that.known
+ && Objects.equals(this.ballot, that.ballot)
+ && Objects.equals(this.localDeps, that.localDeps)
+ && Objects.equals(this.coordinatedDeps,
that.coordinatedDeps);
+ }
}
private LatestDeps()
diff --git a/accord-core/src/main/java/accord/primitives/Range.java
b/accord-core/src/main/java/accord/primitives/Range.java
index 853e9c62..69d0c087 100644
--- a/accord-core/src/main/java/accord/primitives/Range.java
+++ b/accord-core/src/main/java/accord/primitives/Range.java
@@ -489,5 +489,4 @@ public abstract class Range implements
Comparable<RoutableKey>, Unseekable, Seek
{
return (startInclusive() ? "[" : "(") + start().printableSuffix() +
"," + end().printableSuffix() + (endInclusive() ? ']' : ')');
}
-
}
diff --git a/accord-core/src/main/java/accord/primitives/RangeRoute.java
b/accord-core/src/main/java/accord/primitives/RangeRoute.java
index 2bc692ee..a0b4ea51 100644
--- a/accord-core/src/main/java/accord/primitives/RangeRoute.java
+++ b/accord-core/src/main/java/accord/primitives/RangeRoute.java
@@ -185,4 +185,9 @@ public abstract class RangeRoute extends AbstractRanges
implements Route<Range>,
return super.equals(that) &&
homeKey.equals(((RangeRoute)that).homeKey);
}
+ @Override
+ public String toString()
+ {
+ return "{homeKey:" + homeKey + ',' + super.toString() + '}';
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]