This is an automated email from the ASF dual-hosted git repository. ifesdjeen pushed a commit to branch CASSANDRA-20112 in repository https://gitbox.apache.org/repos/asf/cassandra-accord.git
commit 155a67ec810060e48abfe2eefcc8785cd293763b Author: Alex Petrov <[email protected]> AuthorDate: Wed Nov 20 18:05:25 2024 +0100 Nit: make checkstyle happy Add repro for the sorted array issue Randomize cache loading on per-item basis Add comment on fast path tracking --- .../java/accord/coordinate/ExecuteSyncPoint.java | 3 +- .../main/java/accord/coordinate/PersistTxn.java | 1 - .../java/accord/coordinate/RecoverWithRoute.java | 7 +-- .../coordinate/tracking/FastPathTracker.java | 2 +- .../java/accord/impl/InMemoryCommandStore.java | 2 +- .../main/java/accord/messages/BeginRecovery.java | 11 ++-- .../java/accord/primitives/AbstractRanges.java | 14 ++--- accord-core/src/test/java/accord/KeysTest.java | 3 +- .../src/test/java/accord/impl/basic/Cluster.java | 41 ++++++++++--- .../accord/impl/basic/DelayedCommandStores.java | 69 +++++++++++++++++++--- .../src/test/java/accord/impl/basic/Journal.java | 9 +-- .../java/accord/topology/TopologyRandomizer.java | 1 - .../test/java/accord/utils/SortedArraysTest.java | 45 ++++++++------ 13 files changed, 142 insertions(+), 66 deletions(-) diff --git a/accord-core/src/main/java/accord/coordinate/ExecuteSyncPoint.java b/accord-core/src/main/java/accord/coordinate/ExecuteSyncPoint.java index 38cb8bd8..dc010351 100644 --- a/accord-core/src/main/java/accord/coordinate/ExecuteSyncPoint.java +++ b/accord-core/src/main/java/accord/coordinate/ExecuteSyncPoint.java @@ -18,16 +18,15 @@ package accord.coordinate; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.function.Function; import accord.api.Result; import accord.coordinate.CoordinationAdapter.Adapters; -import accord.coordinate.tracking.SimpleTracker; import accord.coordinate.tracking.QuorumTracker; import accord.coordinate.tracking.RequestStatus; +import accord.coordinate.tracking.SimpleTracker; import accord.local.Node; import accord.messages.ApplyThenWaitUntilApplied; import accord.messages.Callback; diff --git a/accord-core/src/main/java/accord/coordinate/PersistTxn.java b/accord-core/src/main/java/accord/coordinate/PersistTxn.java index c9139f01..797e8363 100644 --- a/accord-core/src/main/java/accord/coordinate/PersistTxn.java +++ b/accord-core/src/main/java/accord/coordinate/PersistTxn.java @@ -22,7 +22,6 @@ import accord.api.Result; import accord.local.Node; import accord.primitives.Deps; import accord.primitives.FullRoute; -import accord.primitives.Participants; import accord.primitives.Route; import accord.primitives.Timestamp; import accord.primitives.Txn; diff --git a/accord-core/src/main/java/accord/coordinate/RecoverWithRoute.java b/accord-core/src/main/java/accord/coordinate/RecoverWithRoute.java index 25733111..f969a7e1 100644 --- a/accord-core/src/main/java/accord/coordinate/RecoverWithRoute.java +++ b/accord-core/src/main/java/accord/coordinate/RecoverWithRoute.java @@ -23,8 +23,6 @@ import javax.annotation.Nullable; import accord.local.Node; import accord.local.Node.Id; -import accord.primitives.Status; -import accord.primitives.Known; import accord.messages.CheckStatus; import accord.messages.CheckStatus.CheckStatusOk; import accord.messages.CheckStatus.CheckStatusOkFull; @@ -33,16 +31,16 @@ import accord.messages.Propagate; import accord.primitives.Ballot; import accord.primitives.Deps; import accord.primitives.FullRoute; -import accord.primitives.Participants; +import accord.primitives.Known; import accord.primitives.Ranges; import accord.primitives.Route; +import accord.primitives.Status; import accord.primitives.Txn; import accord.primitives.TxnId; import accord.topology.Topologies; import accord.utils.Invariants; import static accord.coordinate.CoordinationAdapter.Factory.Step.InitiateRecovery; -import static accord.primitives.Status.Durability.Majority; import static accord.primitives.Known.KnownDeps.DepsKnown; import static accord.primitives.Known.KnownExecuteAt.ExecuteAtKnown; import static accord.primitives.Known.Outcome.Apply; @@ -50,6 +48,7 @@ import static accord.primitives.ProgressToken.APPLIED; import static accord.primitives.ProgressToken.INVALIDATED; import static accord.primitives.ProgressToken.TRUNCATED_DURABLE_OR_INVALIDATED; import static accord.primitives.Route.castToFullRoute; +import static accord.primitives.Status.Durability.Majority; import static accord.utils.Invariants.illegalState; public class RecoverWithRoute extends CheckShards<FullRoute<?>> diff --git a/accord-core/src/main/java/accord/coordinate/tracking/FastPathTracker.java b/accord-core/src/main/java/accord/coordinate/tracking/FastPathTracker.java index 81e9d118..271b1395 100644 --- a/accord-core/src/main/java/accord/coordinate/tracking/FastPathTracker.java +++ b/accord-core/src/main/java/accord/coordinate/tracking/FastPathTracker.java @@ -162,7 +162,7 @@ public class FastPathTracker extends PreAcceptTracker<FastPathTracker.FastPathSh ++successes; if (shard.fastPathElectorate.contains(node)) - ++fastPathFailures; + ++fastPathFailures; // Quorum success can not count towards fast path success return quorumIfHasRejectedFastPath(); } diff --git a/accord-core/src/main/java/accord/impl/InMemoryCommandStore.java b/accord-core/src/main/java/accord/impl/InMemoryCommandStore.java index 3ebe7e78..04ea28f4 100644 --- a/accord-core/src/main/java/accord/impl/InMemoryCommandStore.java +++ b/accord-core/src/main/java/accord/impl/InMemoryCommandStore.java @@ -666,7 +666,7 @@ public abstract class InMemoryCommandStore extends CommandStore } } - protected class InMemoryCommandStoreCaches extends AbstractSafeCommandStore.CommandStoreCaches<InMemorySafeCommand, InMemorySafeTimestampsForKey, InMemorySafeCommandsForKey> + public class InMemoryCommandStoreCaches extends AbstractSafeCommandStore.CommandStoreCaches<InMemorySafeCommand, InMemorySafeTimestampsForKey, InMemorySafeCommandsForKey> { @Override public void close() {} diff --git a/accord-core/src/main/java/accord/messages/BeginRecovery.java b/accord-core/src/main/java/accord/messages/BeginRecovery.java index 0ad80f66..4a925a83 100644 --- a/accord-core/src/main/java/accord/messages/BeginRecovery.java +++ b/accord-core/src/main/java/accord/messages/BeginRecovery.java @@ -41,19 +41,18 @@ import accord.topology.Topologies; import accord.utils.Invariants; import accord.utils.async.Cancellable; -import static accord.local.SafeCommandStore.TestDep.WITH_OR_INVALIDATED; import static accord.local.SafeCommandStore.TestDep.WITHOUT; +import static accord.local.SafeCommandStore.TestDep.WITH_OR_INVALIDATED; import static accord.local.SafeCommandStore.TestStartedAt.ANY; -import static accord.local.SafeCommandStore.TestStatus.IS_STABLE; -import static accord.local.SafeCommandStore.TestStatus.IS_PROPOSED; import static accord.local.SafeCommandStore.TestStartedAt.STARTED_AFTER; import static accord.local.SafeCommandStore.TestStartedAt.STARTED_BEFORE; -import static accord.local.SafeCommandStore.TestStatus.IS_STABLE_OR_INVALIDATED; +import static accord.local.SafeCommandStore.TestStatus.IS_PROPOSED; +import static accord.local.SafeCommandStore.TestStatus.IS_STABLE; +import static accord.messages.PreAccept.calculateDeps; +import static accord.primitives.EpochSupplier.constant; import static accord.primitives.Status.Accepted; import static accord.primitives.Status.Phase; import static accord.primitives.Status.PreAccepted; -import static accord.messages.PreAccept.calculateDeps; -import static accord.primitives.EpochSupplier.constant; import static accord.utils.Invariants.illegalState; public class BeginRecovery extends TxnRequest.WithUnsynced<BeginRecovery.RecoverReply> diff --git a/accord-core/src/main/java/accord/primitives/AbstractRanges.java b/accord-core/src/main/java/accord/primitives/AbstractRanges.java index bb85b1d2..4812fed0 100644 --- a/accord-core/src/main/java/accord/primitives/AbstractRanges.java +++ b/accord-core/src/main/java/accord/primitives/AbstractRanges.java @@ -18,6 +18,13 @@ package accord.primitives; +import java.util.Arrays; +import java.util.Iterator; +import java.util.function.Function; +import javax.annotation.Nonnull; + +import com.google.common.collect.Iterators; + import accord.api.RoutingKey; import accord.utils.ArrayBuffers.ObjectBuffers; import accord.utils.IndexedFoldToLong; @@ -26,14 +33,7 @@ import accord.utils.Invariants; import accord.utils.SortedArrays; import net.nicoulaj.compilecommand.annotations.Inline; -import com.google.common.collect.Iterators; - -import javax.annotation.Nonnull; -import java.util.*; -import java.util.function.Function; - import static accord.primitives.Ranges.EMPTY; -import static accord.primitives.Ranges.ofSortedAndDeoverlappedUnchecked; import static accord.utils.ArrayBuffers.cachedRanges; import static accord.utils.Invariants.illegalArgument; import static accord.utils.SortedArrays.Search.CEIL; diff --git a/accord-core/src/test/java/accord/KeysTest.java b/accord-core/src/test/java/accord/KeysTest.java index 67a329e3..3538e21a 100644 --- a/accord-core/src/test/java/accord/KeysTest.java +++ b/accord-core/src/test/java/accord/KeysTest.java @@ -32,10 +32,9 @@ import accord.api.RoutingKey; import accord.impl.IntKey; import accord.impl.IntKey.Raw; import accord.primitives.AbstractKeys; +import accord.primitives.Keys; import accord.primitives.Range; import accord.primitives.Ranges; -import accord.primitives.Keys; - import accord.primitives.RoutableKey; import accord.primitives.Routables; import accord.primitives.RoutingKeys; diff --git a/accord-core/src/test/java/accord/impl/basic/Cluster.java b/accord-core/src/test/java/accord/impl/basic/Cluster.java index dacab032..d712dce3 100644 --- a/accord-core/src/test/java/accord/impl/basic/Cluster.java +++ b/accord-core/src/test/java/accord/impl/basic/Cluster.java @@ -66,10 +66,10 @@ import accord.coordinate.Invalidated; import accord.coordinate.Preempted; import accord.coordinate.Timeout; import accord.coordinate.Truncated; -import accord.impl.DurabilityScheduling; import accord.impl.DefaultLocalListeners; import accord.impl.DefaultRemoteListeners; import accord.impl.DefaultTimeouts; +import accord.impl.DurabilityScheduling; import accord.impl.InMemoryCommandStore.GlobalCommand; import accord.impl.MessageListener; import accord.impl.PrefixedIntHashKey; @@ -86,13 +86,9 @@ import accord.local.DurableBefore; import accord.local.Node; import accord.local.Node.Id; import accord.local.RedundantBefore; +import accord.local.ShardDistributor; import accord.local.StoreParticipants; import accord.local.TimeService; -import accord.primitives.RoutableKey; -import accord.primitives.SaveStatus; -import accord.local.ShardDistributor; -import accord.primitives.Seekables; -import accord.primitives.Status; import accord.local.cfk.CommandsForKey; import accord.messages.Message; import accord.messages.MessageType; @@ -103,6 +99,10 @@ import accord.primitives.FullRoute; import accord.primitives.Keys; import accord.primitives.Range; import accord.primitives.Ranges; +import accord.primitives.RoutableKey; +import accord.primitives.SaveStatus; +import accord.primitives.Seekables; +import accord.primitives.Status; import accord.primitives.Timestamp; import accord.primitives.Txn; import accord.primitives.TxnId; @@ -124,7 +124,6 @@ import static accord.utils.AccordGens.keysInsideRanges; import static accord.utils.AccordGens.rangeInsideRange; import static accord.utils.Gens.mixedDistribution; import static java.util.Collections.emptyMap; -import static java.util.Collections.min; import static java.util.Collections.singletonMap; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.NANOSECONDS; @@ -439,7 +438,6 @@ public class Cluster @Override public Packet get() { - // ((Cluster) node.scheduler()).onDone(() -> checkOnResult(homeKey, txnId, 0, null)); if (requestIterator == null) { Map<Node.Id, Node> nodes = nodeMap.get(); @@ -528,7 +526,32 @@ public class Cluster Journal journal = new Journal(id); journalMap.put(id, journal); BurnTestConfigurationService configService = new BurnTestConfigurationService(id, nodeExecutor, randomSupplier, topology, nodeMap::get, topologyUpdates); - BooleanSupplier isLoadedCheck = Gens.supplier(Gens.bools().mixedDistribution().next(random), random); + DelayedCommandStores.CacheLoadingChance isLoadedCheck = new DelayedCommandStores.CacheLoadingChance() + { + private final BooleanSupplier cacheEmptyChance = Gens.supplier(Gens.bools().mixedDistribution().next(random), random); + public boolean cacheEmpty() + { + return cacheEmptyChance.getAsBoolean(); + } + + private final BooleanSupplier commandLoadedChance = random.biasedUniformBools(0.1f); + public boolean commandLoaded() + { + return commandLoadedChance.getAsBoolean(); + } + + private final BooleanSupplier cfkLoadedChance = random.biasedUniformBools(0.1f); + public boolean cfkLoaded() + { + return cfkLoadedChance.getAsBoolean(); + } + + private final BooleanSupplier tfkLoadedChance = random.biasedUniformBools(0.1f); + public boolean tfkLoaded() + { + return tfkLoadedChance.getAsBoolean(); + } + }; Node node = new Node(id, messageSink, configService, TimeService.ofNonMonotonic(nowSupplier, MILLISECONDS), () -> new ListStore(scheduler, random, id), new ShardDistributor.EvenSplit<>(8, ignore -> new PrefixedIntHashKey.Splitter()), nodeExecutor.agent(), diff --git a/accord-core/src/test/java/accord/impl/basic/DelayedCommandStores.java b/accord-core/src/test/java/accord/impl/basic/DelayedCommandStores.java index 04ac085d..7a41fe72 100644 --- a/accord-core/src/test/java/accord/impl/basic/DelayedCommandStores.java +++ b/accord-core/src/test/java/accord/impl/basic/DelayedCommandStores.java @@ -26,7 +26,6 @@ import java.util.Objects; import java.util.Queue; import java.util.concurrent.Callable; import java.util.function.BiConsumer; -import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.function.Function; @@ -36,6 +35,7 @@ import accord.api.Agent; import accord.api.DataStore; import accord.api.LocalListeners; import accord.api.ProgressLog; +import accord.api.RoutingKey; import accord.impl.InMemoryCommandStore; import accord.impl.InMemoryCommandStores; import accord.impl.InMemorySafeCommand; @@ -70,12 +70,12 @@ import static accord.utils.Invariants.ParanoiaCostFactor.HIGH; public class DelayedCommandStores extends InMemoryCommandStores.SingleThread { - private DelayedCommandStores(NodeCommandStoreService time, Agent agent, DataStore store, RandomSource random, ShardDistributor shardDistributor, ProgressLog.Factory progressLogFactory, LocalListeners.Factory listenersFactory, SimulatedDelayedExecutorService executorService, BooleanSupplier isLoadedCheck, Journal journal) + private DelayedCommandStores(NodeCommandStoreService time, Agent agent, DataStore store, RandomSource random, ShardDistributor shardDistributor, ProgressLog.Factory progressLogFactory, LocalListeners.Factory listenersFactory, SimulatedDelayedExecutorService executorService, CacheLoadingChance isLoadedCheck, Journal journal) { super(time, agent, store, random, shardDistributor, progressLogFactory, listenersFactory, DelayedCommandStore.factory(executorService, isLoadedCheck, journal)); } - public static CommandStores.Factory factory(PendingQueue pending, BooleanSupplier isLoadedCheck, Journal journal) + public static CommandStores.Factory factory(PendingQueue pending, CacheLoadingChance isLoadedCheck, Journal journal) { return (time, agent, store, random, shardDistributor, progressLogFactory, listenersFactory) -> new DelayedCommandStores(time, agent, store, random, shardDistributor, progressLogFactory, listenersFactory, new SimulatedDelayedExecutorService(pending, agent), isLoadedCheck, journal); @@ -131,10 +131,10 @@ public class DelayedCommandStores extends InMemoryCommandStores.SingleThread private final SimulatedDelayedExecutorService executor; private final Queue<Task<?>> pending = new LinkedList<>(); - private final BooleanSupplier isLoadedCheck; + private final CacheLoadingChance isLoadedCheck; private final Journal journal; - public DelayedCommandStore(int id, NodeCommandStoreService time, Agent agent, DataStore store, ProgressLog.Factory progressLogFactory, LocalListeners.Factory listenersFactory, EpochUpdateHolder epochUpdateHolder, SimulatedDelayedExecutorService executor, BooleanSupplier isLoadedCheck, Journal journal) + public DelayedCommandStore(int id, NodeCommandStoreService time, Agent agent, DataStore store, ProgressLog.Factory progressLogFactory, LocalListeners.Factory listenersFactory, EpochUpdateHolder epochUpdateHolder, SimulatedDelayedExecutorService executor, CacheLoadingChance isLoadedCheck, Journal journal) { super(id, time, agent, store, progressLogFactory, listenersFactory, epochUpdateHolder); this.executor = executor; @@ -161,10 +161,10 @@ public class DelayedCommandStores extends InMemoryCommandStores.SingleThread @Override protected boolean canExposeUnloaded() { - return isLoadedCheck.getAsBoolean(); + return !isLoadedCheck.cacheEmpty(); } - private static CommandStore.Factory factory(SimulatedDelayedExecutorService executor, BooleanSupplier isLoadedCheck, Journal journal) + private static CommandStore.Factory factory(SimulatedDelayedExecutorService executor, CacheLoadingChance isLoadedCheck, Journal journal) { return (id, node, agent, store, progressLogFactory, listenersFactory, rangesForEpoch) -> new DelayedCommandStore(id, node, agent, store, progressLogFactory, listenersFactory, rangesForEpoch, executor, isLoadedCheck, journal); } @@ -247,7 +247,7 @@ public class DelayedCommandStores extends InMemoryCommandStores.SingleThread @Override protected InMemorySafeStore createSafeStore(PreLoadContext context, RangesForEpoch ranges, Map<TxnId, InMemorySafeCommand> commands, Map<RoutableKey, InMemorySafeTimestampsForKey> timestampsForKey, Map<RoutableKey, InMemorySafeCommandsForKey> commandsForKeys) { - return new DelayedSafeStore(this, ranges, context, commands, timestampsForKey, commandsForKeys); + return new DelayedSafeStore(this, ranges, context, commands, timestampsForKey, commandsForKeys, isLoadedCheck); } @Override @@ -260,10 +260,18 @@ public class DelayedCommandStores extends InMemoryCommandStores.SingleThread public static class DelayedSafeStore extends InMemoryCommandStore.InMemorySafeStore { private final DelayedCommandStore commandStore; - public DelayedSafeStore(DelayedCommandStore commandStore, RangesForEpoch ranges, PreLoadContext context, Map<TxnId, InMemorySafeCommand> commands, Map<RoutableKey, InMemorySafeTimestampsForKey> timestampsForKey, Map<RoutableKey, InMemorySafeCommandsForKey> commandsForKey) + private final CacheLoadingChance cacheLoadingChance; + public DelayedSafeStore(DelayedCommandStore commandStore, + RangesForEpoch ranges, + PreLoadContext context, + Map<TxnId, InMemorySafeCommand> commands, + Map<RoutableKey, InMemorySafeTimestampsForKey> timestampsForKey, + Map<RoutableKey, InMemorySafeCommandsForKey> commandsForKey, + CacheLoadingChance cacheLoadingChance) { super(commandStore, ranges, context, commands, timestampsForKey, commandsForKey); this.commandStore = commandStore; + this.cacheLoadingChance = cacheLoadingChance; } @Override @@ -280,6 +288,41 @@ public class DelayedCommandStores extends InMemoryCommandStores.SingleThread }); super.postExecute(); } + + @Override + protected InMemoryCommandStore.InMemoryCommandStoreCaches tryGetCaches() + { + if (commandStore.canExposeUnloaded()) + { + return commandStore.new InMemoryCommandStoreCaches() { + @Override + public InMemorySafeCommand acquireIfLoaded(TxnId txnId) + { + if (cacheLoadingChance.commandLoaded()) + return super.acquireIfLoaded(txnId); + return null; + } + + @Override + public InMemorySafeTimestampsForKey acquireTfkIfLoaded(RoutingKey key) + { + if (cacheLoadingChance.tfkLoaded()) + return super.acquireTfkIfLoaded(key); + return null; + } + + @Override + public InMemorySafeCommandsForKey acquireIfLoaded(RoutingKey key) + { + if (cacheLoadingChance.cfkLoaded()) + return super.acquireIfLoaded(key); + return null; + } + }; + } + return null; + + } } public List<DelayedCommandStore> unsafeStores() @@ -289,4 +332,12 @@ public class DelayedCommandStores extends InMemoryCommandStores.SingleThread stores.add((DelayedCommandStore) holder.store); return stores; } + + public interface CacheLoadingChance + { + boolean cacheEmpty(); + boolean commandLoaded(); + boolean cfkLoaded(); + boolean tfkLoaded(); + } } diff --git a/accord-core/src/test/java/accord/impl/basic/Journal.java b/accord-core/src/test/java/accord/impl/basic/Journal.java index f26f1116..ac75af76 100644 --- a/accord-core/src/test/java/accord/impl/basic/Journal.java +++ b/accord-core/src/test/java/accord/impl/basic/Journal.java @@ -20,9 +20,7 @@ package accord.impl.basic; import java.util.AbstractList; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -42,20 +40,19 @@ import accord.local.CommandStore; import accord.local.Commands; import accord.local.CommonAttributes; import accord.local.Node; -import accord.primitives.Known; -import accord.primitives.SaveStatus; -import accord.primitives.Status; import accord.local.StoreParticipants; import accord.primitives.Ballot; +import accord.primitives.Known; import accord.primitives.PartialDeps; import accord.primitives.PartialTxn; +import accord.primitives.SaveStatus; +import accord.primitives.Status; import accord.primitives.Timestamp; import accord.primitives.TxnId; import accord.primitives.Writes; import accord.utils.Invariants; import org.agrona.collections.Long2ObjectHashMap; -import static accord.primitives.SaveStatus.Erased; import static accord.primitives.SaveStatus.NotDefined; import static accord.primitives.SaveStatus.Stable; import static accord.primitives.Status.Invalidated; diff --git a/accord-core/src/test/java/accord/topology/TopologyRandomizer.java b/accord-core/src/test/java/accord/topology/TopologyRandomizer.java index 71a1dc40..ab24cf72 100644 --- a/accord-core/src/test/java/accord/topology/TopologyRandomizer.java +++ b/accord-core/src/test/java/accord/topology/TopologyRandomizer.java @@ -20,7 +20,6 @@ package accord.topology; import java.util.ArrayList; import java.util.Arrays; -import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; diff --git a/accord-core/src/test/java/accord/utils/SortedArraysTest.java b/accord-core/src/test/java/accord/utils/SortedArraysTest.java index 98ce2f59..07f14e6a 100644 --- a/accord-core/src/test/java/accord/utils/SortedArraysTest.java +++ b/accord-core/src/test/java/accord/utils/SortedArraysTest.java @@ -237,24 +237,35 @@ class SortedArraysTest @Test public void testLinearSubtract() { - Gen<Integer[]> gen = sortedUniqueIntegerArray(0); - qt().forAll(gen, gen).check((a, b) -> { - Set<Integer> left = new HashSet<>(Arrays.asList(a)); - Set<Integer> right = new HashSet<>(Arrays.asList(b)); + int[][] quants = {{0, 1000, 0, 1000}, + {0, 100, 0, 1000}, + {0, 100, 0, 10}, + {0, 10, 0, 10}, + {0, 5, 0, 5}, + {0, 5, 0, 5}}; + + for (int[] quant : quants) + { + Gen<Integer[]> gen1 = sortedUniqueIntegerArray(quant[1], quant[0]); + Gen<Integer[]> gen2 = sortedUniqueIntegerArray(quant[3], quant[2]); + qt().forAll(gen1, gen2).withExamples(1000).check((a, b) -> { + Set<Integer> left = new HashSet<>(Arrays.asList(a)); + Set<Integer> right = new HashSet<>(Arrays.asList(b)); - { - Set<Integer> difference = Sets.difference(left, right); - Integer[] expected = toArray(difference, Integer[]::new); - Arrays.sort(expected); - assertArrayEquals(expected, SortedArrays.linearSubtract(a, b, uncached(Integer[]::new))); - } - { - Set<Integer> difference = Sets.difference(right, left); - Integer[] expected = toArray(difference, Integer[]::new); - Arrays.sort(expected); - assertArrayEquals(expected, SortedArrays.linearSubtract(b, a, uncached(Integer[]::new))); - } - }); + { + Set<Integer> difference = Sets.difference(left, right); + Integer[] expected = toArray(difference, Integer[]::new); + Arrays.sort(expected); + assertArrayEquals(expected, SortedArrays.linearSubtract(a, b, uncached(Integer[]::new))); + } + { + Set<Integer> difference = Sets.difference(right, left); + Integer[] expected = toArray(difference, Integer[]::new); + Arrays.sort(expected); + assertArrayEquals(expected, SortedArrays.linearSubtract(b, a, uncached(Integer[]::new))); + } + }); + } } @Test --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
