diff --git a/build.xml b/build.xml index 50937e15ec..3be96e47b9 100644 --- a/build.xml +++ b/build.xml @@ -551,6 +551,7 @@ + @@ -686,6 +687,7 @@ + diff --git a/test/distributed/org/apache/cassandra/distributed/Cluster.java b/test/distributed/org/apache/cassandra/distributed/Cluster.java index d3533d3fa9..ee01874a44 100644 --- a/test/distributed/org/apache/cassandra/distributed/Cluster.java +++ b/test/distributed/org/apache/cassandra/distributed/Cluster.java @@ -24,30 +24,44 @@ import java.util.List; import java.util.function.Consumer; import org.apache.cassandra.distributed.api.ICluster; +import org.apache.cassandra.distributed.api.IInstanceConfig; import org.apache.cassandra.distributed.impl.AbstractCluster; -import org.apache.cassandra.distributed.impl.IInvokableInstance; +import org.apache.cassandra.distributed.api.IInvokableInstance; import org.apache.cassandra.distributed.impl.InstanceConfig; -import org.apache.cassandra.distributed.impl.Versions; +import org.apache.cassandra.distributed.shared.Builder; +import org.apache.cassandra.distributed.shared.NetworkTopology; +import org.apache.cassandra.distributed.shared.Versions; /** * A simple cluster supporting only the 'current' Cassandra version, offering easy access to the convenience methods * of IInvokableInstance on each node. */ -public class Cluster extends AbstractCluster implements ICluster, AutoCloseable +public class Cluster extends AbstractCluster { - private Cluster(File root, Versions.Version version, List configs, ClassLoader sharedClassLoader) + + private Cluster(File root, Versions.Version version, List configs, ClassLoader sharedClassLoader) { super(root, version, configs, sharedClassLoader); } - protected IInvokableInstance newInstanceWrapper(int generation, Versions.Version version, InstanceConfig config) + protected IInvokableInstance newInstanceWrapper(int generation, Versions.Version version, IInstanceConfig config) { return new Wrapper(generation, version, config); } public static Builder build() { - return new Builder<>(Cluster::new); + return new Builder(Cluster::new) + { + { + withVersion(CURRENT_VERSION); + } + + protected IInstanceConfig generateConfig(int nodeNum, String ipAddress, NetworkTopology networkTopology, File root, String token, String seedIp) + { + return InstanceConfig.generate(nodeNum, ipAddress, networkTopology, root, token, seedIp); + } + }; } public static Builder build(int nodeCount) @@ -55,7 +69,7 @@ public class Cluster extends AbstractCluster implements IClu return build().withNodes(nodeCount); } - public static Cluster create(int nodeCount, Consumer configUpdater) throws IOException + public static Cluster create(int nodeCount, Consumer configUpdater) throws IOException { return build(nodeCount).withConfig(configUpdater).start(); } diff --git a/test/distributed/org/apache/cassandra/distributed/UpgradeableCluster.java b/test/distributed/org/apache/cassandra/distributed/UpgradeableCluster.java index 6ffdc6287b..8566897d93 100644 --- a/test/distributed/org/apache/cassandra/distributed/UpgradeableCluster.java +++ b/test/distributed/org/apache/cassandra/distributed/UpgradeableCluster.java @@ -22,11 +22,13 @@ import java.io.File; import java.util.List; import org.apache.cassandra.distributed.api.ICluster; +import org.apache.cassandra.distributed.api.IInstanceConfig; import org.apache.cassandra.distributed.impl.AbstractCluster; -import org.apache.cassandra.distributed.impl.IInvokableInstance; -import org.apache.cassandra.distributed.impl.IUpgradeableInstance; +import org.apache.cassandra.distributed.api.IUpgradeableInstance; import org.apache.cassandra.distributed.impl.InstanceConfig; -import org.apache.cassandra.distributed.impl.Versions; +import org.apache.cassandra.distributed.shared.Builder; +import org.apache.cassandra.distributed.shared.NetworkTopology; +import org.apache.cassandra.distributed.shared.Versions; /** * A multi-version cluster, offering only the cross-version API @@ -35,21 +37,36 @@ import org.apache.cassandra.distributed.impl.Versions; * to permit upgrade tests to perform cluster operations without updating the cross-version API, * so long as one node is up-to-date. */ -public class UpgradeableCluster extends AbstractCluster implements ICluster, AutoCloseable +public class UpgradeableCluster extends AbstractCluster implements AutoCloseable { - private UpgradeableCluster(File root, Versions.Version version, List configs, ClassLoader sharedClassLoader) + private UpgradeableCluster(File root, Versions.Version version, List configs, ClassLoader sharedClassLoader) { super(root, version, configs, sharedClassLoader); } - protected IUpgradeableInstance newInstanceWrapper(int generation, Versions.Version version, InstanceConfig config) + protected IUpgradeableInstance newInstanceWrapper(int generation, Versions.Version version, IInstanceConfig config) { return new Wrapper(generation, version, config); } public static Builder build() { - return new Builder<>(UpgradeableCluster::new); + return new Builder(UpgradeableCluster::new) + { + { + withVersion(CURRENT_VERSION); + } + + protected void setupLogging(File file) + { + setupLogging(file); + } + + protected IInstanceConfig generateConfig(int nodeNum, String ipAddress, NetworkTopology networkTopology, File root, String token, String seedIp) + { + return InstanceConfig.generate(nodeNum, ipAddress, networkTopology, root, token, seedIp); + } + }; } public static Builder build(int nodeCount) diff --git a/test/distributed/org/apache/cassandra/distributed/api/Feature.java b/test/distributed/org/apache/cassandra/distributed/api/Feature.java deleted file mode 100644 index b4ba03630c..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/api/Feature.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.api; - -public enum Feature -{ - NETWORK, GOSSIP, NATIVE_PROTOCOL -} diff --git a/test/distributed/org/apache/cassandra/distributed/api/ICluster.java b/test/distributed/org/apache/cassandra/distributed/api/ICluster.java deleted file mode 100644 index 091e5f048a..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/api/ICluster.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.api; - -import org.apache.cassandra.locator.InetAddressAndPort; - -import java.util.stream.Stream; - -public interface ICluster -{ - - IInstance get(int i); - IInstance get(InetAddressAndPort endpoint); - int size(); - Stream stream(); - Stream stream(String dcName); - Stream stream(String dcName, String rackName); - IMessageFilters filters(); - -} diff --git a/test/distributed/org/apache/cassandra/distributed/api/ICoordinator.java b/test/distributed/org/apache/cassandra/distributed/api/ICoordinator.java deleted file mode 100644 index fe969b181c..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/api/ICoordinator.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.api; - -import java.util.Iterator; -import java.util.UUID; -import java.util.concurrent.Future; - -// The cross-version API requires that a Coordinator can be constructed without any constructor arguments -public interface ICoordinator -{ - // a bit hacky, but ConsistencyLevel draws in too many dependent classes, so we cannot have a cross-version - // method signature that accepts ConsistencyLevel directly. So we just accept an Enum and cast. - default Object[][] execute(String query, Enum consistencyLevel, Object... boundValues) - { - return executeWithResult(query, consistencyLevel, boundValues).toObjectArrays(); - } - QueryResult executeWithResult(String query, Enum consistencyLevel, Object... boundValues); - - Iterator executeWithPaging(String query, Enum consistencyLevel, int pageSize, Object... boundValues); - - Future asyncExecuteWithTracing(UUID sessionId, String query, Enum consistencyLevel, Object... boundValues); - Object[][] executeWithTracing(UUID sessionId, String query, Enum consistencyLevel, Object... boundValues); -} diff --git a/test/distributed/org/apache/cassandra/distributed/api/IInstance.java b/test/distributed/org/apache/cassandra/distributed/api/IInstance.java deleted file mode 100644 index 23ccd7c943..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/api/IInstance.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.api; - -import org.apache.cassandra.locator.InetAddressAndPort; - -import java.util.UUID; -import java.util.concurrent.Future; - -// The cross-version API requires that an Instance has a constructor signature of (IInstanceConfig, ClassLoader) -public interface IInstance extends IIsolatedExecutor -{ - ICoordinator coordinator(); - IListen listen(); - - void schemaChangeInternal(String query); - public Object[][] executeInternal(String query, Object... args); - - IInstanceConfig config(); - public InetAddressAndPort broadcastAddressAndPort(); - UUID schemaVersion(); - - void startup(); - boolean isShutdown(); - Future shutdown(); - Future shutdown(boolean graceful); - - int liveMemberCount(); - - NodeToolResult nodetoolResult(boolean withNotifications, String... commandAndArgs); - default NodeToolResult nodetoolResult(String... commandAndArgs) - { - return nodetoolResult(true, commandAndArgs); - } - default int nodetool(String... commandAndArgs) { - return nodetoolResult(commandAndArgs).getRc(); - } - void uncaughtException(Thread t, Throwable e); - - /** - * Return the number of times the instance tried to call {@link System#exit(int)}. - * - * When the instance is shutdown, this state should be saved, but in case not possible should return {@code -1} - * to indicate "unknown". - */ - long killAttempts(); - - // these methods are not for external use, but for simplicity we leave them public and on the normal IInstance interface - void startup(ICluster cluster); - void receiveMessage(IMessage message); - - int getMessagingVersion(); - void setMessagingVersion(InetAddressAndPort endpoint, int version); - - void flush(String keyspace); - void forceCompact(String keyspace, String table); -} diff --git a/test/distributed/org/apache/cassandra/distributed/api/IInstanceConfig.java b/test/distributed/org/apache/cassandra/distributed/api/IInstanceConfig.java deleted file mode 100644 index e451441897..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/api/IInstanceConfig.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.api; - -import org.apache.cassandra.distributed.impl.NetworkTopology; -import org.apache.cassandra.locator.InetAddressAndPort; -import org.apache.cassandra.utils.Pair; - -import java.util.Map; -import java.util.UUID; - -public interface IInstanceConfig -{ - int num(); - UUID hostId(); - InetAddressAndPort broadcastAddressAndPort(); - NetworkTopology networkTopology(); - - default public String localRack() - { - return networkTopology().localRack(broadcastAddressAndPort()); - } - - default public String localDatacenter() - { - return networkTopology().localDC(broadcastAddressAndPort()); - } - - /** - * write the specified parameters to the Config object; we do not specify Config as the type to support a Config - * from any ClassLoader; the implementation must not directly access any fields of the Object, or cast it, but - * must use the reflection API to modify the state - */ - void propagate(Object writeToConfig); - - /** - * Validates whether the config properties are within range of accepted values. - */ - void validate(); - Object get(String fieldName); - String getString(String fieldName); - int getInt(String fieldName); - boolean has(Feature featureFlag); -} diff --git a/test/distributed/org/apache/cassandra/distributed/api/IIsolatedExecutor.java b/test/distributed/org/apache/cassandra/distributed/api/IIsolatedExecutor.java deleted file mode 100644 index 6bb41d7969..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/api/IIsolatedExecutor.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.api; - -import java.io.Serializable; -import java.util.concurrent.Callable; -import java.util.concurrent.Future; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.function.Function; - -/** - * Represents a clean way to handoff evaluation of some work to an executor associated - * with a node's lifetime. - * - * There is no transfer of execution to the parallel class hierarchy. - * - * Classes, such as Instance, that are themselves instantiated on the correct ClassLoader, utilise this class - * to ensure the lifetime of any thread evaluating one of its method invocations matches the lifetime of the class itself. - * Since they are instantiated on the correct ClassLoader, sharing only the interface, there is no serialization necessary. - */ -public interface IIsolatedExecutor -{ - public interface CallableNoExcept extends Callable { public O call(); } - public interface SerializableCallable extends CallableNoExcept, Serializable { } - public interface SerializableRunnable extends Runnable, Serializable {} - public interface SerializableConsumer extends Consumer, Serializable {} - public interface SerializableBiConsumer extends BiConsumer, Serializable {} - public interface SerializableFunction extends Function, Serializable {} - public interface SerializableBiFunction extends BiFunction, Serializable {} - public interface TriFunction - { - O apply(I1 i1, I2 i2, I3 i3); - } - public interface SerializableTriFunction extends Serializable, TriFunction { } - - Future shutdown(); - - /** - * Convert the execution to one performed asynchronously on the IsolatedExecutor, returning a Future of the execution result - */ - CallableNoExcept> async(CallableNoExcept call); - - /** - * Convert the execution to one performed synchronously on the IsolatedExecutor - */ - CallableNoExcept sync(CallableNoExcept call); - - /** - * Convert the execution to one performed asynchronously on the IsolatedExecutor, returning a Future of the execution result - */ - CallableNoExcept> async(Runnable run); - - /** - * Convert the execution to one performed synchronously on the IsolatedExecutor - */ - Runnable sync(Runnable run); - - /** - * Convert the execution to one performed asynchronously on the IsolatedExecutor, returning a Future of the execution result - */ - Function> async(Consumer consumer); - - /** - * Convert the execution to one performed synchronously on the IsolatedExecutor - */ - Consumer sync(Consumer consumer); - - /** - * Convert the execution to one performed asynchronously on the IsolatedExecutor, returning a Future of the execution result - */ - BiFunction> async(BiConsumer consumer); - - /** - * Convert the execution to one performed synchronously on the IsolatedExecutor - */ - BiConsumer sync(BiConsumer consumer); - - /** - * Convert the execution to one performed asynchronously on the IsolatedExecutor, returning a Future of the execution result - */ - Function> async(Function f); - - /** - * Convert the execution to one performed synchronously on the IsolatedExecutor - */ - Function sync(Function f); - - /** - * Convert the execution to one performed asynchronously on the IsolatedExecutor, returning a Future of the execution result - */ - BiFunction> async(BiFunction f); - - /** - * Convert the execution to one performed synchronously on the IsolatedExecutor - */ - BiFunction sync(BiFunction f); - - /** - * Convert the execution to one performed asynchronously on the IsolatedExecutor, returning a Future of the execution result - */ - TriFunction> async(TriFunction f); - - /** - * Convert the execution to one performed synchronously on the IsolatedExecutor - */ - TriFunction sync(TriFunction f); - -} diff --git a/test/distributed/org/apache/cassandra/distributed/api/IMessage.java b/test/distributed/org/apache/cassandra/distributed/api/IMessage.java deleted file mode 100644 index f2594caa7a..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/api/IMessage.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.api; - -import java.io.Serializable; - -import org.apache.cassandra.locator.InetAddressAndPort; - -/** - * A cross-version interface for delivering internode messages via message sinks. - * - * Message implementations should be serializable so we could load into instances. - */ -public interface IMessage extends Serializable -{ - int verb(); - byte[] bytes(); - // TODO: need to make this a long - int id(); - int version(); - InetAddressAndPort from(); -} diff --git a/test/distributed/org/apache/cassandra/distributed/api/IMessageFilters.java b/test/distributed/org/apache/cassandra/distributed/api/IMessageFilters.java deleted file mode 100644 index f2cd6ee232..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/api/IMessageFilters.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.api; - -import java.util.function.Predicate; - -public interface IMessageFilters -{ - public interface Filter - { - Filter off(); - Filter on(); - } - - public interface Builder - { - Builder from(int ... nums); - Builder to(int ... nums); - - Builder verbs(int... verbs); - Builder allVerbs(); - - Builder inbound(boolean inbound); - - default Builder inbound() - { - return inbound(true); - } - - default Builder outbound() - { - return inbound(false); - } - - /** - * Every message for which matcher returns `true` will be _dropped_ (assuming all - * other matchers in the chain will return `true` as well). - */ - Builder messagesMatching(Matcher filter); - Filter drop(); - } - - public interface Matcher - { - boolean matches(int from, int to, IMessage message); - - static Matcher of(Predicate fn) { - return (from, to, m) -> fn.test(m); - } - } - - Builder inbound(boolean inbound); - default Builder inbound() { - return inbound(true); - } - default Builder outbound() { - return inbound(false); - } - default Builder verbs(int... verbs) { - return inbound().verbs(verbs); - } - default Builder allVerbs() { - return inbound().allVerbs(); - } - void reset(); - - /** - * Checks if the message should be delivered. This is expected to run on "inbound", or on the reciever of - * the message (instance.config.num == to). - * - * @return {@code true} value returned by the implementation implies that the message was - * not matched by any filters and therefore should be delivered. - */ - boolean permitInbound(int from, int to, IMessage msg); - - /** - * Checks if the message should be delivered. This is expected to run on "outbound", or on the sender of - * the message (instance.config.num == from). - * - * @return {@code true} value returned by the implementation implies that the message was - * not matched by any filters and therefore should be delivered. - */ - boolean permitOutbound(int from, int to, IMessage msg); -} diff --git a/test/distributed/org/apache/cassandra/distributed/impl/AbstractCluster.java b/test/distributed/org/apache/cassandra/distributed/impl/AbstractCluster.java index 371de54f0c..bcfaaf5157 100644 --- a/test/distributed/org/apache/cassandra/distributed/impl/AbstractCluster.java +++ b/test/distributed/org/apache/cassandra/distributed/impl/AbstractCluster.java @@ -19,10 +19,7 @@ package org.apache.cassandra.distributed.impl; import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; +import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -35,7 +32,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.stream.Collectors; -import java.util.stream.IntStream; import java.util.stream.Stream; import com.google.common.collect.Sets; @@ -43,8 +39,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.cassandra.db.ColumnFamilyStore; -import org.apache.cassandra.db.ConsistencyLevel; import org.apache.cassandra.db.Keyspace; +import org.apache.cassandra.distributed.api.ConsistencyLevel; import org.apache.cassandra.distributed.api.Feature; import org.apache.cassandra.distributed.api.ICluster; import org.apache.cassandra.dht.IPartitioner; @@ -52,13 +48,18 @@ import org.apache.cassandra.dht.Token; import org.apache.cassandra.distributed.api.ICoordinator; import org.apache.cassandra.distributed.api.IInstance; import org.apache.cassandra.distributed.api.IInstanceConfig; +import org.apache.cassandra.distributed.api.IInvokableInstance; import org.apache.cassandra.distributed.api.IIsolatedExecutor; import org.apache.cassandra.distributed.api.IListen; import org.apache.cassandra.distributed.api.IMessage; import org.apache.cassandra.distributed.api.IMessageFilters; +import org.apache.cassandra.distributed.api.IUpgradeableInstance; import org.apache.cassandra.distributed.api.NodeToolResult; +import org.apache.cassandra.distributed.shared.InstanceClassLoader; +import org.apache.cassandra.distributed.shared.MessageFilters; +import org.apache.cassandra.distributed.shared.NetworkTopology; +import org.apache.cassandra.distributed.shared.Versions; import org.apache.cassandra.io.util.FileUtils; -import org.apache.cassandra.locator.InetAddressAndPort; import org.apache.cassandra.net.Verb; import org.apache.cassandra.utils.FBUtilities; import org.apache.cassandra.utils.concurrent.SimpleCondition; @@ -87,8 +88,10 @@ import org.apache.cassandra.utils.concurrent.SimpleCondition; * handlers for internode to have more control over it. Messaging is wired by passing verbs manually. * coordinator-handling code and hooks to the callbacks can be found in {@link Coordinator}. */ -public abstract class AbstractCluster implements ICluster, AutoCloseable +public abstract class AbstractCluster implements ICluster, AutoCloseable { + public static Versions.Version CURRENT_VERSION = new Versions.Version(FBUtilities.getReleaseVersionString(), Versions.getClassPath());; + // WARNING: we have this logger not (necessarily) for logging, but // to ensure we have instantiated the main classloader's LoggerFactory (and any LogbackStatusListener) // before we instantiate any for a new instance @@ -100,7 +103,7 @@ public abstract class AbstractCluster implements ICluster, // mutated by starting/stopping a node private final List instances; - private final Map instanceMap; + private final Map instanceMap; private final Versions.Version initialVersion; @@ -111,7 +114,7 @@ public abstract class AbstractCluster implements ICluster, protected class Wrapper extends DelegatingInvokableInstance implements IUpgradeableInstance { private final int generation; - private final InstanceConfig config; + private final IInstanceConfig config; private volatile IInvokableInstance delegate; private volatile Versions.Version version; private volatile boolean isShutdown = true; @@ -123,7 +126,7 @@ public abstract class AbstractCluster implements ICluster, return delegate; } - public Wrapper(int generation, Versions.Version version, InstanceConfig config) + public Wrapper(int generation, Versions.Version version, IInstanceConfig config) { this.generation = generation; this.config = config; @@ -134,9 +137,9 @@ public abstract class AbstractCluster implements ICluster, private IInvokableInstance newInstance(int generation) { - ClassLoader classLoader = new InstanceClassLoader(generation, config.num, version.classpath, sharedClassLoader); - return Instance.transferAdhoc((SerializableBiFunction) Instance::new, classLoader) - .apply(config.forVersion(version.major), classLoader); + ClassLoader classLoader = new InstanceClassLoader(generation, config.num(), version.classpath, sharedClassLoader); + return Instance.transferAdhoc((SerializableBiFunction)Instance::new, classLoader) + .apply(config.forVersion(version.major), classLoader); } public IInstanceConfig config() @@ -158,7 +161,7 @@ public abstract class AbstractCluster implements ICluster, public synchronized void startup(ICluster cluster) { if (cluster != AbstractCluster.this) - throw new IllegalArgumentException("Only the owning cluster can be used for startup"); //TODO why have this in the API? + throw new IllegalArgumentException("Only the owning cluster can be used for startup"); if (!isShutdown) throw new IllegalStateException(); delegate().startup(cluster); @@ -238,7 +241,7 @@ public abstract class AbstractCluster implements ICluster, } } - protected AbstractCluster(File root, Versions.Version initialVersion, List configs, + protected AbstractCluster(File root, Versions.Version initialVersion, List configs, ClassLoader sharedClassLoader) { this.root = root; @@ -248,27 +251,27 @@ public abstract class AbstractCluster implements ICluster, this.initialVersion = initialVersion; int generation = AbstractCluster.generation.incrementAndGet(); - for (InstanceConfig config : configs) + for (IInstanceConfig config : configs) { I instance = newInstanceWrapperInternal(generation, initialVersion, config); instances.add(instance); // we use the config().broadcastAddressAndPort() here because we have not initialised the Instance - I prev = instanceMap.put(instance.broadcastAddressAndPort(), instance); + I prev = instanceMap.put(instance.broadcastAddress(), instance); if (null != prev) - throw new IllegalStateException("Cluster cannot have multiple nodes with same InetAddressAndPort: " + instance.broadcastAddressAndPort() + " vs " + prev.broadcastAddressAndPort()); + throw new IllegalStateException("Cluster cannot have multiple nodes with same InetAddressAndPort: " + instance.broadcastAddress() + " vs " + prev.broadcastAddress()); } this.filters = new MessageFilters(); } - protected abstract I newInstanceWrapper(int generation, Versions.Version version, InstanceConfig config); + protected abstract I newInstanceWrapper(int generation, Versions.Version version, IInstanceConfig config); - protected I newInstanceWrapperInternal(int generation, Versions.Version version, InstanceConfig config) + protected I newInstanceWrapperInternal(int generation, Versions.Version version, IInstanceConfig config) { config.validate(); return newInstanceWrapper(generation, version, config); } - public I bootstrap(InstanceConfig config) + public I bootstrap(IInstanceConfig config) { if (!config.has(Feature.GOSSIP) || !config.has(Feature.NETWORK)) throw new IllegalStateException("New nodes can only be bootstrapped when gossip and networking is enabled."); @@ -276,12 +279,13 @@ public abstract class AbstractCluster implements ICluster, I instance = newInstanceWrapperInternal(0, initialVersion, config); instances.add(instance); - I prev = instanceMap.put(config.broadcastAddressAndPort(), instance); + + I prev = instanceMap.put(config.broadcastAddress(), instance); if (null != prev) { throw new IllegalStateException(String.format("This cluster already contains a node (%d) with with same address and port: %s", - config.num, + config.num(), instance)); } @@ -304,7 +308,7 @@ public abstract class AbstractCluster implements ICluster, return instances.get(node - 1); } - public I get(InetAddressAndPort addr) + public I get(InetSocketAddress addr) { return instanceMap.get(addr); } @@ -391,6 +395,11 @@ public abstract class AbstractCluster implements ICluster, }).run(); } + public void schemaChange(String statement, int instance) + { + get(instance).schemaChangeInternal(statement); + } + private void updateMessagingVersions() { for (IInstance reportTo : instances) @@ -404,7 +413,7 @@ public abstract class AbstractCluster implements ICluster, continue; int minVersion = Math.min(reportFrom.getMessagingVersion(), reportTo.getMessagingVersion()); - reportTo.setMessagingVersion(reportFrom.broadcastAddressAndPort(), minVersion); + reportTo.setMessagingVersion(reportFrom.broadcastAddress(), minVersion); } } } @@ -524,12 +533,7 @@ public abstract class AbstractCluster implements ICluster, } } - public void schemaChange(String statement, int instance) - { - get(instance).schemaChangeInternal(statement); - } - - void startup() + public void startup() { previousHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this::uncaughtExceptions); @@ -569,257 +573,6 @@ public abstract class AbstractCluster implements ICluster, get(cl.getInstanceId()).uncaughtException(thread, error); } - protected interface Factory> - { - C newCluster(File root, Versions.Version version, List configs, ClassLoader sharedClassLoader); - } - - public static class Builder> - { - private final Factory factory; - private int nodeCount; - private int subnet; - private Map nodeIdTopology; - private TokenSupplier tokenSupplier; - private File root; - private Versions.Version version = Versions.CURRENT; - private Consumer configUpdater; - - public Builder(Factory factory) - { - this.factory = factory; - } - - public Builder withTokenSupplier(TokenSupplier tokenSupplier) - { - this.tokenSupplier = tokenSupplier; - return this; - } - - public Builder withSubnet(int subnet) - { - this.subnet = subnet; - return this; - } - - public Builder withNodes(int nodeCount) - { - this.nodeCount = nodeCount; - return this; - } - - public Builder withDCs(int dcCount) - { - return withRacks(dcCount, 1); - } - - public Builder withRacks(int dcCount, int racksPerDC) - { - if (nodeCount == 0) - throw new IllegalStateException("Node count will be calculated. Do not supply total node count in the builder"); - - int totalRacks = dcCount * racksPerDC; - int nodesPerRack = (nodeCount + totalRacks - 1) / totalRacks; // round up to next integer - return withRacks(dcCount, racksPerDC, nodesPerRack); - } - - public Builder withRacks(int dcCount, int racksPerDC, int nodesPerRack) - { - if (nodeIdTopology != null) - throw new IllegalStateException("Network topology already created. Call withDCs/withRacks once or before withDC/withRack calls"); - - nodeIdTopology = new HashMap<>(); - int nodeId = 1; - for (int dc = 1; dc <= dcCount; dc++) - { - for (int rack = 1; rack <= racksPerDC; rack++) - { - for (int rackNodeIdx = 0; rackNodeIdx < nodesPerRack; rackNodeIdx++) - nodeIdTopology.put(nodeId++, NetworkTopology.dcAndRack(dcName(dc), rackName(rack))); - } - } - // adjust the node count to match the allocatation - final int adjustedNodeCount = dcCount * racksPerDC * nodesPerRack; - if (adjustedNodeCount != nodeCount) - { - assert adjustedNodeCount > nodeCount : "withRacks should only ever increase the node count"; - logger.info("Network topology of {} DCs with {} racks per DC and {} nodes per rack required increasing total nodes to {}", - dcCount, racksPerDC, nodesPerRack, adjustedNodeCount); - nodeCount = adjustedNodeCount; - } - return this; - } - - public Builder withDC(String dcName, int nodeCount) - { - return withRack(dcName, rackName(1), nodeCount); - } - - public Builder withRack(String dcName, String rackName, int nodesInRack) - { - if (nodeIdTopology == null) - { - if (nodeCount > 0) - throw new IllegalStateException("Node count must not be explicitly set, or allocated using withDCs/withRacks"); - - nodeIdTopology = new HashMap<>(); - } - for (int nodeId = nodeCount + 1; nodeId <= nodeCount + nodesInRack; nodeId++) - nodeIdTopology.put(nodeId, NetworkTopology.dcAndRack(dcName, rackName)); - - nodeCount += nodesInRack; - return this; - } - - // Map of node ids to dc and rack - must be contiguous with an entry nodeId 1 to nodeCount - public Builder withNodeIdTopology(Map nodeIdTopology) - { - if (nodeIdTopology.isEmpty()) - throw new IllegalStateException("Topology is empty. It must have an entry for every nodeId."); - - IntStream.rangeClosed(1, nodeIdTopology.size()).forEach(nodeId -> { - if (nodeIdTopology.get(nodeId) == null) - throw new IllegalStateException("Topology is missing entry for nodeId " + nodeId); - }); - - if (nodeCount != nodeIdTopology.size()) - { - nodeCount = nodeIdTopology.size(); - logger.info("Adjusting node count to {} for supplied network topology", nodeCount); - } - - this.nodeIdTopology = new HashMap<>(nodeIdTopology); - - return this; - } - - public Builder withRoot(File root) - { - this.root = root; - return this; - } - - public Builder withVersion(Versions.Version version) - { - this.version = version; - return this; - } - - public Builder withConfig(Consumer updater) - { - this.configUpdater = updater; - return this; - } - - public C createWithoutStarting() throws IOException - { - if (root == null) - root = Files.createTempDirectory("dtests").toFile(); - - if (nodeCount <= 0) - throw new IllegalStateException("Cluster must have at least one node"); - - if (nodeIdTopology == null) - { - nodeIdTopology = IntStream.rangeClosed(1, nodeCount).boxed() - .collect(Collectors.toMap(nodeId -> nodeId, - nodeId -> NetworkTopology.dcAndRack(dcName(0), rackName(0)))); - } - - root.mkdirs(); - setupLogging(root); - - ClassLoader sharedClassLoader = Thread.currentThread().getContextClassLoader(); - - List configs = new ArrayList<>(); - - if (tokenSupplier == null) - tokenSupplier = evenlyDistributedTokens(nodeCount); - - for (int i = 0; i < nodeCount; ++i) - { - int nodeNum = i + 1; - configs.add(createInstanceConfig(nodeNum)); - } - - return factory.newCluster(root, version, configs, sharedClassLoader); - } - - public InstanceConfig newInstanceConfig(C cluster) - { - return createInstanceConfig(cluster.size() + 1); - } - - private InstanceConfig createInstanceConfig(int nodeNum) - { - String ipPrefix = "127.0." + subnet + "."; - String seedIp = ipPrefix + "1"; - String ipAddress = ipPrefix + nodeNum; - long token = tokenSupplier.token(nodeNum); - - NetworkTopology topology = NetworkTopology.build(ipPrefix, 7012, nodeIdTopology); - - InstanceConfig config = InstanceConfig.generate(nodeNum, ipAddress, topology, root, String.valueOf(token), seedIp); - if (configUpdater != null) - configUpdater.accept(config); - - return config; - } - - public C start() throws IOException - { - C cluster = createWithoutStarting(); - cluster.startup(); - return cluster; - } - } - - public static TokenSupplier evenlyDistributedTokens(int numNodes) - { - long increment = (Long.MAX_VALUE / numNodes) * 2; - return (int nodeId) -> { - assert nodeId <= numNodes : String.format("Can not allocate a token for a node %s, since only %s nodes are allowed by the token allocation strategy", - nodeId, numNodes); - return Long.MIN_VALUE + 1 + nodeId * increment; - }; - } - - public static interface TokenSupplier - { - public long token(int nodeId); - } - - static String dcName(int index) - { - return "datacenter" + index; - } - - static String rackName(int index) - { - return "rack" + index; - } - - private static void setupLogging(File root) - { - try - { - String testConfPath = "test/conf/logback-dtest.xml"; - Path logConfPath = Paths.get(root.getPath(), "/logback-dtest.xml"); - - if (!logConfPath.toFile().exists()) - { - Files.copy(new File(testConfPath).toPath(), - logConfPath); - } - - System.setProperty("logback.configurationFile", "file://" + logConfPath); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } - @Override public void close() { diff --git a/test/distributed/org/apache/cassandra/distributed/impl/Coordinator.java b/test/distributed/org/apache/cassandra/distributed/impl/Coordinator.java index dee9049db9..c1446d109e 100644 --- a/test/distributed/org/apache/cassandra/distributed/impl/Coordinator.java +++ b/test/distributed/org/apache/cassandra/distributed/impl/Coordinator.java @@ -32,8 +32,9 @@ import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryProcessor; import org.apache.cassandra.cql3.UntypedResultSet; import org.apache.cassandra.cql3.statements.SelectStatement; -import org.apache.cassandra.db.ConsistencyLevel; +import org.apache.cassandra.distributed.api.ConsistencyLevel; import org.apache.cassandra.distributed.api.ICoordinator; +import org.apache.cassandra.distributed.api.IInstance; import org.apache.cassandra.distributed.api.QueryResult; import org.apache.cassandra.service.ClientState; import org.apache.cassandra.service.QueryState; @@ -53,12 +54,12 @@ public class Coordinator implements ICoordinator } @Override - public QueryResult executeWithResult(String query, Enum consistencyLevel, Object... boundValues) + public QueryResult executeWithResult(String query, ConsistencyLevel consistencyLevel, Object... boundValues) { - return instance.sync(() -> executeInternal(query, consistencyLevel, boundValues)).call(); + return instance().sync(() -> executeInternal(query, consistencyLevel, boundValues)).call(); } - public Future asyncExecuteWithTracing(UUID sessionId, String query, Enum consistencyLevelOrigin, Object... boundValues) + public Future asyncExecuteWithTracing(UUID sessionId, String query, ConsistencyLevel consistencyLevelOrigin, Object... boundValues) { return instance.async(() -> { try @@ -73,7 +74,12 @@ public class Coordinator implements ICoordinator }).call(); } - private QueryResult executeInternal(String query, Enum consistencyLevelOrigin, Object[] boundValues) + protected org.apache.cassandra.db.ConsistencyLevel toCassandraCL(ConsistencyLevel cl) + { + return org.apache.cassandra.db.ConsistencyLevel.fromCode(cl.ordinal()); + } + + private QueryResult executeInternal(String query, ConsistencyLevel consistencyLevelOrigin, Object[] boundValues) { ClientState clientState = makeFakeClientState(); CQLStatement prepared = QueryProcessor.getStatement(query, clientState); @@ -84,7 +90,7 @@ public class Coordinator implements ICoordinator prepared.validate(QueryState.forInternalCalls().getClientState()); ResultMessage res = prepared.execute(QueryState.forInternalCalls(), - QueryOptions.create(consistencyLevel, + QueryOptions.create(toCassandraCL(consistencyLevel), boundBBValues, false, Integer.MAX_VALUE, @@ -107,13 +113,18 @@ public class Coordinator implements ICoordinator } } - public Object[][] executeWithTracing(UUID sessionId, String query, Enum consistencyLevelOrigin, Object... boundValues) + public Object[][] executeWithTracing(UUID sessionId, String query, ConsistencyLevel consistencyLevelOrigin, Object... boundValues) { return IsolatedExecutor.waitOn(asyncExecuteWithTracing(sessionId, query, consistencyLevelOrigin, boundValues)); } + public IInstance instance() + { + return instance; + } + @Override - public Iterator executeWithPaging(String query, Enum consistencyLevelOrigin, int pageSize, Object... boundValues) + public Iterator executeWithPaging(String query, ConsistencyLevel consistencyLevelOrigin, int pageSize, Object... boundValues) { if (pageSize <= 0) throw new IllegalArgumentException("Page size should be strictly positive but was " + pageSize); @@ -133,7 +144,7 @@ public class Coordinator implements ICoordinator SelectStatement selectStatement = (SelectStatement) prepared; - QueryPager pager = selectStatement.getQuery(QueryOptions.create(consistencyLevel, + QueryPager pager = selectStatement.getQuery(QueryOptions.create(toCassandraCL(consistencyLevel), boundBBValues, false, pageSize, @@ -147,7 +158,7 @@ public class Coordinator implements ICoordinator // Usually pager fetches a single page (see SelectStatement#execute). We need to iterate over all // of the results lazily. return new Iterator() { - Iterator iter = RowUtil.toObjects(UntypedResultSet.create(selectStatement, consistencyLevel, clientState, pager, pageSize)); + Iterator iter = RowUtil.toObjects(UntypedResultSet.create(selectStatement, toCassandraCL(consistencyLevel), clientState, pager, pageSize)); public boolean hasNext() { diff --git a/test/distributed/org/apache/cassandra/distributed/impl/DelegatingInvokableInstance.java b/test/distributed/org/apache/cassandra/distributed/impl/DelegatingInvokableInstance.java index 72949447eb..2f7a043a71 100644 --- a/test/distributed/org/apache/cassandra/distributed/impl/DelegatingInvokableInstance.java +++ b/test/distributed/org/apache/cassandra/distributed/impl/DelegatingInvokableInstance.java @@ -19,6 +19,7 @@ package org.apache.cassandra.distributed.impl; import java.io.Serializable; +import java.net.InetSocketAddress; import java.util.UUID; import java.util.concurrent.Future; import java.util.function.BiConsumer; @@ -29,9 +30,10 @@ import java.util.function.Function; import org.apache.cassandra.distributed.api.ICluster; import org.apache.cassandra.distributed.api.ICoordinator; import org.apache.cassandra.distributed.api.IInstanceConfig; +import org.apache.cassandra.distributed.api.IInvokableInstance; import org.apache.cassandra.distributed.api.IListen; import org.apache.cassandra.distributed.api.IMessage; -import org.apache.cassandra.locator.InetAddressAndPort; +import org.apache.cassandra.distributed.shared.NetworkTopology; public abstract class DelegatingInvokableInstance implements IInvokableInstance { @@ -44,9 +46,9 @@ public abstract class DelegatingInvokableInstance implements IInvokableInstance } @Override - public InetAddressAndPort broadcastAddressAndPort() + public InetSocketAddress broadcastAddress() { - return delegate().broadcastAddressAndPort(); + return delegate().broadcastAddress(); } @Override @@ -80,7 +82,7 @@ public abstract class DelegatingInvokableInstance implements IInvokableInstance } @Override - public void setMessagingVersion(InetAddressAndPort endpoint, int version) + public void setMessagingVersion(InetSocketAddress endpoint, int version) { delegate().setMessagingVersion(endpoint, version); } diff --git a/test/distributed/org/apache/cassandra/distributed/impl/DistributedTestSnitch.java b/test/distributed/org/apache/cassandra/distributed/impl/DistributedTestSnitch.java index 736e77bb27..e671f4d9bc 100644 --- a/test/distributed/org/apache/cassandra/distributed/impl/DistributedTestSnitch.java +++ b/test/distributed/org/apache/cassandra/distributed/impl/DistributedTestSnitch.java @@ -19,10 +19,13 @@ package org.apache.cassandra.distributed.impl; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.apache.cassandra.config.Config; import org.apache.cassandra.db.SystemKeyspace; +import org.apache.cassandra.distributed.shared.NetworkTopology; import org.apache.cassandra.gms.ApplicationState; import org.apache.cassandra.gms.EndpointState; import org.apache.cassandra.gms.Gossiper; @@ -34,6 +37,30 @@ import org.apache.cassandra.utils.FBUtilities; public class DistributedTestSnitch extends AbstractNetworkTopologySnitch { private static NetworkTopology mapping = null; + private static final Map cache = new ConcurrentHashMap<>(); + private static final Map cacheInverse = new ConcurrentHashMap<>(); + + static InetAddressAndPort toCassandraInetAddressAndPort(InetSocketAddress addressAndPort) + { + InetAddressAndPort m = cacheInverse.get(addressAndPort); + if (m == null) + { + m = InetAddressAndPort.getByAddressOverrideDefaults(addressAndPort.getAddress(), addressAndPort.getPort()); + cache.put(m, addressAndPort); + } + return m; + } + + static InetSocketAddress fromCassandraInetAddressAndPort(InetAddressAndPort addressAndPort) + { + InetSocketAddress m = cache.get(addressAndPort); + if (m == null) + { + m = NetworkTopology.addressAndPort(addressAndPort.address, addressAndPort.port); + cache.put(addressAndPort, m); + } + return m; + } private Map> savedEndpoints; private static final String DEFAULT_DC = "UNKNOWN_DC"; @@ -48,7 +75,7 @@ public class DistributedTestSnitch extends AbstractNetworkTopologySnitch public String getRack(InetAddressAndPort endpoint) { assert mapping != null : "network topology must be assigned before using snitch"; - return maybeGetFromEndpointState(mapping.localRack(endpoint), endpoint, ApplicationState.RACK, DEFAULT_RACK); + return maybeGetFromEndpointState(mapping.localRack(fromCassandraInetAddressAndPort(endpoint)), endpoint, ApplicationState.RACK, DEFAULT_RACK); } public String getDatacenter(InetAddress endpoint) @@ -60,7 +87,7 @@ public class DistributedTestSnitch extends AbstractNetworkTopologySnitch public String getDatacenter(InetAddressAndPort endpoint) { assert mapping != null : "network topology must be assigned before using snitch"; - return maybeGetFromEndpointState(mapping.localDC(endpoint), endpoint, ApplicationState.DC, DEFAULT_DC); + return maybeGetFromEndpointState(mapping.localDC(fromCassandraInetAddressAndPort(endpoint)), endpoint, ApplicationState.DC, DEFAULT_DC); } // Here, the logic is slightly different from what we have in GossipingPropertyFileSnitch since we have a different diff --git a/test/distributed/org/apache/cassandra/distributed/impl/IInvokableInstance.java b/test/distributed/org/apache/cassandra/distributed/impl/IInvokableInstance.java deleted file mode 100644 index d0f8a5f9f0..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/impl/IInvokableInstance.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.impl; - -import java.io.Serializable; -import java.util.concurrent.Future; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.function.Function; - -import org.apache.cassandra.distributed.api.IInstance; - -/** - * This version is only supported for a Cluster running the same code as the test environment, and permits - * ergonomic cross-node behaviours, without editing the cross-version API. - * - * A lambda can be written tto be invoked on any or all of the nodes. - * - * The reason this cannot (easily) be made cross-version is that the lambda is tied to the declaring class, which will - * not be the same in the alternate version. Even were it not, there would likely be a runtime linkage error given - * any code divergence. - */ -public interface IInvokableInstance extends IInstance -{ - public default CallableNoExcept> asyncCallsOnInstance(SerializableCallable call) { return async(transfer(call)); } - public default CallableNoExcept callsOnInstance(SerializableCallable call) { return sync(transfer(call)); } - public default O callOnInstance(SerializableCallable call) { return callsOnInstance(call).call(); } - - public default CallableNoExcept> asyncRunsOnInstance(SerializableRunnable run) { return async(transfer(run)); } - public default Runnable runsOnInstance(SerializableRunnable run) { return sync(transfer(run)); } - public default void runOnInstance(SerializableRunnable run) { runsOnInstance(run).run(); } - - public default Function> asyncAcceptsOnInstance(SerializableConsumer consumer) { return async(transfer(consumer)); } - public default Consumer acceptsOnInstance(SerializableConsumer consumer) { return sync(transfer(consumer)); } - - public default BiFunction> asyncAcceptsOnInstance(SerializableBiConsumer consumer) { return async(transfer(consumer)); } - public default BiConsumer acceptsOnInstance(SerializableBiConsumer consumer) { return sync(transfer(consumer)); } - - public default Function> asyncAppliesOnInstance(SerializableFunction f) { return async(transfer(f)); } - public default Function appliesOnInstance(SerializableFunction f) { return sync(transfer(f)); } - - public default BiFunction> asyncAppliesOnInstance(SerializableBiFunction f) { return async(transfer(f)); } - public default BiFunction appliesOnInstance(SerializableBiFunction f) { return sync(transfer(f)); } - - public default TriFunction> asyncAppliesOnInstance(SerializableTriFunction f) { return async(transfer(f)); } - public default TriFunction appliesOnInstance(SerializableTriFunction f) { return sync(transfer(f)); } - - public E transfer(E object); - -} diff --git a/test/distributed/org/apache/cassandra/distributed/impl/IUpgradeableInstance.java b/test/distributed/org/apache/cassandra/distributed/impl/IUpgradeableInstance.java deleted file mode 100644 index 3eb3657d4d..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/impl/IUpgradeableInstance.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.impl; - -import org.apache.cassandra.distributed.api.IInstance; - -// this lives outside the api package so that we do not have to worry about inter-version compatibility -public interface IUpgradeableInstance extends IInstance -{ - // only to be invoked while the node is shutdown! - public void setVersion(Versions.Version version); -} diff --git a/test/distributed/org/apache/cassandra/distributed/impl/Instance.java b/test/distributed/org/apache/cassandra/distributed/impl/Instance.java index 90d747ef9d..e79a182dfe 100644 --- a/test/distributed/org/apache/cassandra/distributed/impl/Instance.java +++ b/test/distributed/org/apache/cassandra/distributed/impl/Instance.java @@ -20,15 +20,21 @@ package org.apache.cassandra.distributed.impl; import java.io.File; import java.io.IOException; +import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.TimeoutException; +import java.util.function.BiConsumer; +import java.util.function.Function; + import javax.management.ListenerNotFoundException; import javax.management.Notification; import javax.management.NotificationListener; @@ -59,11 +65,13 @@ import org.apache.cassandra.dht.Token; import org.apache.cassandra.distributed.api.ICluster; import org.apache.cassandra.distributed.api.ICoordinator; import org.apache.cassandra.distributed.api.IInstanceConfig; +import org.apache.cassandra.distributed.api.IInvokableInstance; import org.apache.cassandra.distributed.api.IListen; import org.apache.cassandra.distributed.api.IMessage; import org.apache.cassandra.distributed.api.NodeToolResult; import org.apache.cassandra.distributed.mock.nodetool.InternalNodeProbe; import org.apache.cassandra.distributed.mock.nodetool.InternalNodeProbeFactory; +import org.apache.cassandra.distributed.shared.NetworkTopology; import org.apache.cassandra.gms.ApplicationState; import org.apache.cassandra.gms.Gossiper; import org.apache.cassandra.gms.VersionedValue; @@ -105,9 +113,18 @@ import static java.util.concurrent.TimeUnit.MINUTES; import static org.apache.cassandra.distributed.api.Feature.GOSSIP; import static org.apache.cassandra.distributed.api.Feature.NATIVE_PROTOCOL; import static org.apache.cassandra.distributed.api.Feature.NETWORK; +import static org.apache.cassandra.distributed.impl.DistributedTestSnitch.fromCassandraInetAddressAndPort; +import static org.apache.cassandra.distributed.impl.DistributedTestSnitch.toCassandraInetAddressAndPort; public class Instance extends IsolatedExecutor implements IInvokableInstance { + private static final Map, Function> mapper = new HashMap, Function>() {{ + this.put(IInstanceConfig.ParameterizedClass.class, (obj) -> { + IInstanceConfig.ParameterizedClass pc = (IInstanceConfig.ParameterizedClass) obj; + return new org.apache.cassandra.config.ParameterizedClass(pc.class_name, pc.parameters); + }); + }}; + public final IInstanceConfig config; // should never be invoked directly, so that it is instantiated on other class loader; @@ -117,7 +134,9 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance super("node" + config.num(), classLoader); this.config = config; InstanceIDDefiner.setInstanceId(config.num()); - FBUtilities.setBroadcastInetAddressAndPort(config.broadcastAddressAndPort()); + FBUtilities.setBroadcastInetAddressAndPort(InetAddressAndPort.getByAddressOverrideDefaults(config.broadcastAddress().getAddress(), + config.broadcastAddress().getPort())); + // Set the config at instance creation, possibly before startup() has run on all other instances. // setMessagingVersions below will call runOnInstance which will instantiate // the MessagingService and dependencies preventing later changes to network parameters. @@ -146,7 +165,7 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance } @Override - public InetAddressAndPort broadcastAddressAndPort() { return config.broadcastAddressAndPort(); } + public InetSocketAddress broadcastAddress() { return config.broadcastAddress(); } @Override public Object[][] executeInternal(String query, Object... args) @@ -206,36 +225,30 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance private void registerMockMessaging(ICluster cluster) { MessagingService.instance().outboundSink.add((message, to) -> { - cluster.get(to).receiveMessage(serializeMessage(message.from(), to, message)); + InetSocketAddress toAddr = fromCassandraInetAddressAndPort(to); + cluster.get(toAddr).receiveMessage(serializeMessage(message.from(), to, message)); return false; }); } private void registerInboundFilter(ICluster cluster) { - MessagingService.instance().inboundSink.add(message -> - permitMessageInbound(cluster, serializeMessage(message.from(), broadcastAddressAndPort(), message))); + MessagingService.instance().inboundSink.add(message -> { + IMessage serialized = serializeMessage(message.from(), toCassandraInetAddressAndPort(broadcastAddress()), message); + int fromNum = cluster.get(serialized.from()).config().num(); + int toNum = config.num(); // since this instance is reciving the message, to will always be this instance + return cluster.filters().permitInbound(fromNum, toNum, serialized); + }); } private void registerOutboundFilter(ICluster cluster) { - - MessagingService.instance().outboundSink.add((message, to) -> - permitMessageOutbound(cluster, to, serializeMessage(message.from(), to, message))); - } - - private boolean permitMessageInbound(ICluster cluster, IMessage message) - { - int fromNum = cluster.get(message.from()).config().num(); - int toNum = config.num(); // since this instance is reciving the message, to will always be this instance - return cluster.filters().permitInbound(fromNum, toNum, message); - } - - private boolean permitMessageOutbound(ICluster cluster, InetAddressAndPort to, IMessage message) - { - int fromNum = config.num(); // since this instance is sending the message, from will always be this instance - int toNum = cluster.get(to).config().num(); - return cluster.filters().permitOutbound(fromNum, toNum, message); + MessagingService.instance().outboundSink.add((message, to) -> { + IMessage serialzied = serializeMessage(message.from(), to, message); + int fromNum = config.num(); // since this instance is sending the message, from will always be this instance + int toNum = cluster.get(fromCassandraInetAddressAndPort(to)).config().num(); + return cluster.filters().permitOutbound(fromNum, toNum, serialzied); + }); } public void uncaughtException(Thread thread, Throwable throwable) @@ -249,7 +262,7 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance { int version = MessagingService.instance().versions.get(to); Message.serializer.serialize(messageOut, out, version); - return new MessageImpl(messageOut.verb().id, out.toByteArray(), messageOut.id(), version, from); + return new MessageImpl(messageOut.verb().id, out.toByteArray(), messageOut.id(), version, fromCassandraInetAddressAndPort(from)); } catch (IOException e) { @@ -262,7 +275,7 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance { try (DataInputBuffer in = new DataInputBuffer(message.bytes())) { - return Message.serializer.deserialize(in, message.from(), message.version()); + return Message.serializer.deserialize(in, toCassandraInetAddressAndPort(message.from()), message.version()); } catch (Throwable t) { @@ -286,9 +299,8 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance Message.Header header = messageIn.header; TraceState state = Tracing.instance.initializeFromMessage(header); if (state != null) state.trace("{} message received from {}", header.verb, header.from); - header.verb.stage.execute(() -> { - MessagingService.instance().inboundSink.accept(messageIn); - }, ExecutorLocals.create(state)); + header.verb.stage.execute(() -> MessagingService.instance().inboundSink.accept(messageIn), + ExecutorLocals.create(state)); }).run(); } @@ -297,9 +309,10 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance return callsOnInstance(() -> MessagingService.current_version).call(); } - public void setMessagingVersion(InetAddressAndPort endpoint, int version) + @Override + public void setMessagingVersion(InetSocketAddress endpoint, int version) { - MessagingService.instance().versions.set(endpoint, version); + MessagingService.instance().versions.set(toCassandraInetAddressAndPort(endpoint), version); } public void flush(String keyspace) @@ -339,7 +352,8 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance mkdirs(); - assert config.networkTopology().contains(config.broadcastAddressAndPort()); + assert config.networkTopology().contains(config.broadcastAddress()) : String.format("Network topology %s doesn't contain the address %s", + config.networkTopology(), config.broadcastAddress()); DistributedTestSnitch.assign(config.networkTopology()); DatabaseDescriptor.daemonInitialization(); @@ -386,6 +400,7 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance } registerInboundFilter(cluster); registerOutboundFilter(cluster); + JVMStabilityInspector.replaceKiller(new InstanceKiller()); // TODO: this is more than just gossip @@ -393,6 +408,7 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance { StorageService.instance.initServer(); StorageService.instance.removeShutdownHook(); + Gossiper.waitToSettle(); } else { @@ -413,8 +429,9 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance StorageService.instance.setRpcReady(true); } - if (!FBUtilities.getBroadcastAddressAndPort().equals(broadcastAddressAndPort())) - throw new IllegalStateException(); + if (!FBUtilities.getBroadcastAddressAndPort().address.equals(broadcastAddress().getAddress()) || + FBUtilities.getBroadcastAddressAndPort().port != broadcastAddress().getPort()) + throw new IllegalStateException(String.format("%s != %s", FBUtilities.getBroadcastAddressAndPort(), broadcastAddress())); ActiveRepairService.instance.start(); } @@ -436,10 +453,10 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance new File(dir).mkdirs(); } - private static Config loadConfig(IInstanceConfig overrides) + private Config loadConfig(IInstanceConfig overrides) { Config config = new Config(); - overrides.propagate(config); + overrides.propagate(config, mapper); return config; } @@ -448,13 +465,13 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance // This should be done outside instance in order to avoid serializing config String partitionerName = config.getString("partitioner"); List initialTokens = new ArrayList<>(); - List hosts = new ArrayList<>(); + List hosts = new ArrayList<>(); List hostIds = new ArrayList<>(); for (int i = 1 ; i <= cluster.size() ; ++i) { IInstanceConfig config = cluster.get(i).config(); initialTokens.add(config.getString("initial_token")); - hosts.add(config.broadcastAddressAndPort()); + hosts.add(config.broadcastAddress()); hostIds.add(config.hostId()); } @@ -468,32 +485,33 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance for (int i = 0; i < tokens.size(); i++) { - InetAddressAndPort ep = hosts.get(i); + InetSocketAddress ep = hosts.get(i); + InetAddressAndPort addressAndPort = toCassandraInetAddressAndPort(ep); UUID hostId = hostIds.get(i); Token token = tokens.get(i); Gossiper.runInGossipStageBlocking(() -> { - Gossiper.instance.initializeNodeUnsafe(ep, hostId, 1); - Gossiper.instance.injectApplicationState(ep, + Gossiper.instance.initializeNodeUnsafe(addressAndPort, hostId, 1); + Gossiper.instance.injectApplicationState(addressAndPort, ApplicationState.TOKENS, new VersionedValue.VersionedValueFactory(partitioner).tokens(Collections.singleton(token))); - storageService.onChange(ep, + storageService.onChange(addressAndPort, ApplicationState.STATUS_WITH_PORT, new VersionedValue.VersionedValueFactory(partitioner).normal(Collections.singleton(token))); - storageService.onChange(ep, + storageService.onChange(addressAndPort, ApplicationState.STATUS, new VersionedValue.VersionedValueFactory(partitioner).normal(Collections.singleton(token))); - Gossiper.instance.realMarkAlive(ep, Gossiper.instance.getEndpointStateForEndpoint(ep)); + Gossiper.instance.realMarkAlive(addressAndPort, Gossiper.instance.getEndpointStateForEndpoint(addressAndPort)); }); int messagingVersion = cluster.get(ep).isShutdown() ? MessagingService.current_version : Math.min(MessagingService.current_version, cluster.get(ep).getMessagingVersion()); - MessagingService.instance().versions.set(ep, messagingVersion); + MessagingService.instance().versions.set(addressAndPort, messagingVersion); } // check that all nodes are in token metadata for (int i = 0; i < tokens.size(); ++i) - assert storageService.getTokenMetadata().isMember(hosts.get(i)); + assert storageService.getTokenMetadata().isMember(toCassandraInetAddressAndPort(hosts.get(i))); } catch (Throwable e) // UnknownHostException { @@ -621,8 +639,9 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance } } - private static final class CollectingNotificationListener implements NotificationListener { - private final CopyOnWriteArrayList notifications = new CopyOnWriteArrayList<>(); + private static final class CollectingNotificationListener implements NotificationListener + { + private final List notifications = new CopyOnWriteArrayList<>(); public void handleNotification(Notification notification, Object handback) { diff --git a/test/distributed/org/apache/cassandra/distributed/impl/InstanceClassLoader.java b/test/distributed/org/apache/cassandra/distributed/impl/InstanceClassLoader.java deleted file mode 100644 index 75a8912c5e..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/impl/InstanceClassLoader.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.impl; - -import com.google.common.base.Predicate; -import org.apache.cassandra.config.ParameterizedClass; -import org.apache.cassandra.io.util.DataOutputPlus; -import org.apache.cassandra.io.util.Memory; -import org.apache.cassandra.locator.InetAddressAndPort; -import org.apache.cassandra.utils.Pair; - -import java.io.IOException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Arrays; -import java.util.Set; -import java.util.stream.Collectors; - -public class InstanceClassLoader extends URLClassLoader -{ - // Classes that have to be shared between instances, for configuration or returning values - private static final Set sharedClassNames = Arrays.stream(new Class[] - { - Pair.class, - InetAddressAndPort.class, - ParameterizedClass.class, - IInvokableInstance.class, - NetworkTopology.class - }) - .map(Class::getName) - .collect(Collectors.toSet()); - - private static final Predicate sharePackage = name -> - name.startsWith("org.apache.cassandra.distributed.api.") - || name.startsWith("sun.") - || name.startsWith("oracle.") - || name.startsWith("com.intellij.") - || name.startsWith("com.sun.") - || name.startsWith("com.oracle.") - || name.startsWith("java.") - || name.startsWith("javax.") - || name.startsWith("jdk.") - || name.startsWith("netscape.") - || name.startsWith("org.xml.sax."); - - private static final Predicate shareClass = name -> sharePackage.apply(name) || sharedClassNames.contains(name); - - public static interface Factory - { - InstanceClassLoader create(int id, URL[] urls, ClassLoader sharedClassLoader); - } - - private volatile boolean isClosed = false; - private final URL[] urls; - private final int generation; // used to help debug class loader leaks, by helping determine which classloaders should have been collected - private final int id; - private final ClassLoader sharedClassLoader; - - InstanceClassLoader(int generation, int id, URL[] urls, ClassLoader sharedClassLoader) - { - super(urls, null); - this.urls = urls; - this.sharedClassLoader = sharedClassLoader; - this.generation = generation; - this.id = id; - } - - public int getClusterGeneration() - { - return generation; - } - - public int getInstanceId() - { - return id; - } - - @Override - public Class loadClass(String name) throws ClassNotFoundException - { - if (shareClass.apply(name)) - return sharedClassLoader.loadClass(name); - - return loadClassInternal(name); - } - - Class loadClassInternal(String name) throws ClassNotFoundException - { - if (isClosed) - throw new IllegalStateException(String.format("Can't load %s. Instance class loader is already closed.", name)); - - synchronized (getClassLoadingLock(name)) - { - // First, check if the class has already been loaded - Class c = findLoadedClass(name); - - if (c == null) - c = findClass(name); - - return c; - } - } - - /** - * @return true iff this class was loaded by an InstanceClassLoader, and as such is used by a dtest node - */ - public static boolean wasLoadedByAnInstanceClassLoader(Class clazz) - { - return clazz.getClassLoader().getClass().getName().equals(InstanceClassLoader.class.getName()); - } - - public String toString() - { - return "InstanceClassLoader{" + - "generation=" + generation + - ", id = " + id + - ", urls=" + Arrays.toString(urls) + - '}'; - } - - public void close() throws IOException - { - isClosed = true; - super.close(); - } -} diff --git a/test/distributed/org/apache/cassandra/distributed/impl/InstanceConfig.java b/test/distributed/org/apache/cassandra/distributed/impl/InstanceConfig.java index ad4f6bfb93..9e2d9d633c 100644 --- a/test/distributed/org/apache/cassandra/distributed/impl/InstanceConfig.java +++ b/test/distributed/org/apache/cassandra/distributed/impl/InstanceConfig.java @@ -18,16 +18,9 @@ package org.apache.cassandra.distributed.impl; -import org.apache.cassandra.config.Config; -import org.apache.cassandra.config.ParameterizedClass; -import org.apache.cassandra.distributed.api.Feature; -import org.apache.cassandra.distributed.api.IInstanceConfig; -import org.apache.cassandra.exceptions.ConfigurationException; -import org.apache.cassandra.locator.InetAddressAndPort; -import org.apache.cassandra.locator.SimpleSeedProvider; - import java.io.File; import java.lang.reflect.Field; +import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.Arrays; import java.util.Collections; @@ -35,6 +28,14 @@ import java.util.EnumSet; import java.util.Map; import java.util.TreeMap; import java.util.UUID; +import java.util.function.Function; + +import org.apache.cassandra.distributed.api.Feature; +import org.apache.cassandra.distributed.api.IInstanceConfig; +import org.apache.cassandra.distributed.shared.NetworkTopology; +import org.apache.cassandra.distributed.shared.Versions; +import org.apache.cassandra.locator.InetAddressAndPort; +import org.apache.cassandra.locator.SimpleSeedProvider; public class InstanceConfig implements IInstanceConfig { @@ -54,28 +55,6 @@ public class InstanceConfig implements IInstanceConfig private volatile InetAddressAndPort broadcastAddressAndPort; - @Override - public InetAddressAndPort broadcastAddressAndPort() - { - if (broadcastAddressAndPort == null) - { - broadcastAddressAndPort = getAddressAndPortFromConfig("broadcast_address", "storage_port"); - } - return broadcastAddressAndPort; - } - - private InetAddressAndPort getAddressAndPortFromConfig(String addressProp, String portProp) - { - try - { - return InetAddressAndPort.getByNameOverrideDefaults(getString(addressProp), getInt(portProp)); - } - catch (UnknownHostException e) - { - throw new IllegalStateException(e); - } - } - private InstanceConfig(int num, NetworkTopology networkTopology, String broadcast_address, @@ -117,7 +96,7 @@ public class InstanceConfig implements IInstanceConfig .set("storage_port", 7012) .set("endpoint_snitch", DistributedTestSnitch.class.getName()) .set("seed_provider", new ParameterizedClass(SimpleSeedProvider.class.getName(), - Collections.singletonMap("seeds", seedIp + ":7012"))) + Collections.singletonMap("seeds", seedIp + ":7012"))) // required settings for dtest functionality .set("diagnostic_events_enabled", true) .set("auto_bootstrap", false) @@ -140,6 +119,44 @@ public class InstanceConfig implements IInstanceConfig this.broadcastAddressAndPort = copy.broadcastAddressAndPort; } + + @Override + public InetSocketAddress broadcastAddress() + { + return DistributedTestSnitch.fromCassandraInetAddressAndPort(getBroadcastAddressAndPort()); + } + + protected InetAddressAndPort getBroadcastAddressAndPort() + { + if (broadcastAddressAndPort == null) + { + broadcastAddressAndPort = getAddressAndPortFromConfig("broadcast_address", "storage_port"); + } + return broadcastAddressAndPort; + } + + private InetAddressAndPort getAddressAndPortFromConfig(String addressProp, String portProp) + { + try + { + return InetAddressAndPort.getByNameOverrideDefaults(getString(addressProp), getInt(portProp)); + } + catch (UnknownHostException e) + { + throw new IllegalStateException(e); + } + } + + public String localRack() + { + return networkTopology().localRack(broadcastAddress()); + } + + public String localDatacenter() + { + return networkTopology().localDC(broadcastAddress()); + } + public InstanceConfig with(Feature featureFlag) { featureFlags.add(featureFlag); @@ -163,8 +180,6 @@ public class InstanceConfig implements IInstanceConfig if (value == null) value = NULL; - // test value - propagate(new Config(), fieldName, value, false); params.put(fieldName, value); return this; } @@ -179,16 +194,10 @@ public class InstanceConfig implements IInstanceConfig return this; } - public void propagateIfSet(Object writeToConfig, String fieldName) - { - if (params.containsKey(fieldName)) - propagate(writeToConfig, fieldName, params.get(fieldName), true); - } - - public void propagate(Object writeToConfig) + public void propagate(Object writeToConfig, Map, Function> mapping) { for (Map.Entry e : params.entrySet()) - propagate(writeToConfig, e.getKey(), e.getValue(), true); + propagate(writeToConfig, e.getKey(), e.getValue(), mapping); } public void validate() @@ -197,11 +206,14 @@ public class InstanceConfig implements IInstanceConfig throw new IllegalArgumentException("In-JVM dtests do not support vnodes as of now."); } - private void propagate(Object writeToConfig, String fieldName, Object value, boolean ignoreMissing) + private void propagate(Object writeToConfig, String fieldName, Object value, Map, Function> mapping) { if (value == NULL) value = null; + if (mapping != null && mapping.containsKey(value.getClass())) + value = mapping.get(value.getClass()).apply(value); + Class configClass = writeToConfig.getClass(); Field valueField; try @@ -210,9 +222,7 @@ public class InstanceConfig implements IInstanceConfig } catch (NoSuchFieldException e) { - if (!ignoreMissing) - throw new IllegalStateException(e); - return; + throw new IllegalStateException(e); } if (valueField.getType().isEnum() && value instanceof String) diff --git a/test/distributed/org/apache/cassandra/distributed/impl/IsolatedExecutor.java b/test/distributed/org/apache/cassandra/distributed/impl/IsolatedExecutor.java index 248155a7e2..fc31fdf978 100644 --- a/test/distributed/org/apache/cassandra/distributed/impl/IsolatedExecutor.java +++ b/test/distributed/org/apache/cassandra/distributed/impl/IsolatedExecutor.java @@ -39,6 +39,7 @@ import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; import org.slf4j.LoggerFactory; @@ -101,6 +102,9 @@ public class IsolatedExecutor implements IIsolatedExecutor }); } + public Supplier> supplyAsync(SerializableSupplier call) { return () -> isolatedExecutor.submit(call::get); } + public Supplier supplySync(SerializableSupplier call) { return () -> waitOn(supplyAsync(call).get()); } + public CallableNoExcept> async(CallableNoExcept call) { return () -> isolatedExecutor.submit(call); } public CallableNoExcept sync(CallableNoExcept call) { return () -> waitOn(async(call).call()); } diff --git a/test/distributed/org/apache/cassandra/distributed/impl/MessageFilters.java b/test/distributed/org/apache/cassandra/distributed/impl/MessageFilters.java deleted file mode 100644 index b4017e1b70..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/impl/MessageFilters.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.impl; - -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.cassandra.distributed.api.IMessage; -import org.apache.cassandra.distributed.api.IMessageFilters; - -public class MessageFilters implements IMessageFilters -{ - private final List inboundFilters = new CopyOnWriteArrayList<>(); - private final List outboundFilters = new CopyOnWriteArrayList<>(); - - public boolean permitInbound(int from, int to, IMessage msg) - { - return permit(inboundFilters, from, to, msg); - } - - public boolean permitOutbound(int from, int to, IMessage msg) - { - return permit(outboundFilters, from, to, msg); - } - - private static boolean permit(List filters, int from, int to, IMessage msg) - { - for (Filter filter : filters) - { - if (filter.matches(from, to, msg)) - return false; - } - return true; - } - - public static class Filter implements IMessageFilters.Filter - { - final List parent; - final int[] from; - final int[] to; - final int[] verbs; - final Matcher matcher; - - private Filter(List parent, int[] from, int[] to, int[] verbs, Matcher matcher) - { - if (from != null) - { - from = from.clone(); - Arrays.sort(from); - } - if (to != null) - { - to = to.clone(); - Arrays.sort(to); - } - if (verbs != null) - { - verbs = verbs.clone(); - Arrays.sort(verbs); - } - this.parent = Objects.requireNonNull(parent, "parent"); - this.from = from; - this.to = to; - this.verbs = verbs; - this.matcher = matcher; - } - - public int hashCode() - { - return (from == null ? 0 : Arrays.hashCode(from)) - + (to == null ? 0 : Arrays.hashCode(to)) - + (verbs == null ? 0 : Arrays.hashCode(verbs) - + parent.hashCode()); - } - - public boolean equals(Object that) - { - return that instanceof Filter && equals((Filter) that); - } - - public boolean equals(Filter that) - { - return Arrays.equals(from, that.from) - && Arrays.equals(to, that.to) - && Arrays.equals(verbs, that.verbs) - && parent.equals(that.parent); - } - - public Filter off() - { - parent.remove(this); - return this; - } - - public Filter on() - { - parent.add(this); - return this; - } - - public boolean matches(int from, int to, IMessage msg) - { - return (this.from == null || Arrays.binarySearch(this.from, from) >= 0) - && (this.to == null || Arrays.binarySearch(this.to, to) >= 0) - && (this.verbs == null || Arrays.binarySearch(this.verbs, msg.verb()) >= 0) - && (this.matcher == null || this.matcher.matches(from, to, msg)); - } - } - - public class Builder implements IMessageFilters.Builder - { - boolean inbound; - int[] from; - int[] to; - int[] verbs; - Matcher matcher; - - private Builder(boolean inbound) - { - this.inbound = inbound; - } - - public IMessageFilters.Builder from(int... nums) - { - from = nums; - return this; - } - - public IMessageFilters.Builder to(int... nums) - { - to = nums; - return this; - } - - public IMessageFilters.Builder verbs(int... verbs) - { - this.verbs = verbs; - return this; - } - - public IMessageFilters.Builder allVerbs() - { - this.verbs = null; - return this; - } - - public IMessageFilters.Builder inbound(boolean inbound) - { - this.inbound = inbound; - return this; - } - - public IMessageFilters.Builder messagesMatching(Matcher matcher) - { - this.matcher = matcher; - return this; - } - - public IMessageFilters.Filter drop() - { - return new Filter(inbound ? inboundFilters : outboundFilters, from, to, verbs, matcher).on(); - } - } - - - public IMessageFilters.Builder inbound(boolean inbound) - { - return new Builder(inbound); - } - - @Override - public void reset() - { - inboundFilters.clear(); - outboundFilters.clear(); - } -} diff --git a/test/distributed/org/apache/cassandra/distributed/impl/MessageImpl.java b/test/distributed/org/apache/cassandra/distributed/impl/MessageImpl.java index e5c72c5438..ebc31b1225 100644 --- a/test/distributed/org/apache/cassandra/distributed/impl/MessageImpl.java +++ b/test/distributed/org/apache/cassandra/distributed/impl/MessageImpl.java @@ -18,8 +18,10 @@ package org.apache.cassandra.distributed.impl; +import java.net.InetSocketAddress; + import org.apache.cassandra.distributed.api.IMessage; -import org.apache.cassandra.locator.InetAddressAndPort; +import org.apache.cassandra.distributed.shared.NetworkTopology; // a container for simplifying the method signature for per-instance message handling/delivery public class MessageImpl implements IMessage @@ -28,9 +30,9 @@ public class MessageImpl implements IMessage public final byte[] bytes; public final long id; public final int version; - public final InetAddressAndPort from; + public final InetSocketAddress from; - public MessageImpl(int verb, byte[] bytes, long id, int version, InetAddressAndPort from) + public MessageImpl(int verb, byte[] bytes, long id, int version, InetSocketAddress from) { this.verb = verb; this.bytes = bytes; @@ -59,7 +61,7 @@ public class MessageImpl implements IMessage return version; } - public InetAddressAndPort from() + public InetSocketAddress from() { return from; } diff --git a/test/distributed/org/apache/cassandra/distributed/impl/NetworkTopology.java b/test/distributed/org/apache/cassandra/distributed/impl/NetworkTopology.java deleted file mode 100644 index f7c31ff2c8..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/impl/NetworkTopology.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.impl; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.HashMap; -import java.util.Map; -import java.util.function.IntFunction; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import org.apache.cassandra.exceptions.ConfigurationException; -import org.apache.cassandra.locator.InetAddressAndPort; -import org.apache.cassandra.utils.Pair; - -public class NetworkTopology -{ - private final Map map; - - public static class DcAndRack - { - private final String dc; - private final String rack; - - private DcAndRack(String dc, String rack) - { - this.dc = dc; - this.rack = rack; - } - } - - public static DcAndRack dcAndRack(String dc, String rack) - { - return new DcAndRack(dc, rack); - } - - private NetworkTopology() { - map = new HashMap<>(); - } - - @SuppressWarnings("WeakerAccess") - public NetworkTopology(NetworkTopology networkTopology) - { - map = new HashMap<>(networkTopology.map); - } - - public static NetworkTopology build(String ipPrefix, int broadcastPort, Map nodeIdTopology) - { - final NetworkTopology topology = new NetworkTopology(); - - for (int nodeId = 1; nodeId <= nodeIdTopology.size(); nodeId++) - { - String broadcastAddress = ipPrefix + nodeId; - - try - { - DcAndRack dcAndRack = nodeIdTopology.get(nodeId); - if (dcAndRack == null) - throw new IllegalStateException("nodeId " + nodeId + "not found in instanceMap"); - - InetAddressAndPort broadcastAddressAndPort = InetAddressAndPort.getByAddressOverrideDefaults( - InetAddress.getByName(broadcastAddress), broadcastPort); - topology.put(broadcastAddressAndPort, dcAndRack); - } - catch (UnknownHostException e) - { - throw new ConfigurationException("Unknown broadcast_address '" + broadcastAddress + '\'', false); - } - } - return topology; - } - - public DcAndRack put(InetAddressAndPort key, DcAndRack value) - { - return map.put(key, value); - } - - public String localRack(InetAddressAndPort key) - { - DcAndRack p = map.get(key); - if (p == null) - return null; - return p.rack; - } - - public String localDC(InetAddressAndPort key) - { - DcAndRack p = map.get(key); - if (p == null) - return null; - return p.dc; - } - - public boolean contains(InetAddressAndPort key) - { - return map.containsKey(key); - } - - public String toString() - { - return "NetworkTopology{" + map + '}'; - } - - - public static Map singleDcNetworkTopology(int nodeCount, - String dc, - String rack) - { - return networkTopology(nodeCount, (nodeid) -> NetworkTopology.dcAndRack(dc, rack)); - } - - public static Map networkTopology(int nodeCount, - IntFunction dcAndRackSupplier) - { - - return IntStream.rangeClosed(1, nodeCount).boxed() - .collect(Collectors.toMap(nodeId -> nodeId, - dcAndRackSupplier::apply)); - } -} diff --git a/test/distributed/org/apache/cassandra/distributed/impl/TracingUtil.java b/test/distributed/org/apache/cassandra/distributed/impl/TracingUtil.java index d671e553d9..439d4b74b3 100644 --- a/test/distributed/org/apache/cassandra/distributed/impl/TracingUtil.java +++ b/test/distributed/org/apache/cassandra/distributed/impl/TracingUtil.java @@ -24,7 +24,7 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; -import org.apache.cassandra.db.ConsistencyLevel; +import org.apache.cassandra.distributed.api.ConsistencyLevel; /** diff --git a/test/distributed/org/apache/cassandra/distributed/impl/Versions.java b/test/distributed/org/apache/cassandra/distributed/impl/Versions.java deleted file mode 100644 index 5d67f684a4..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/impl/Versions.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.impl; - -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.cassandra.config.Config; -import org.apache.cassandra.utils.FBUtilities; - -public class Versions -{ - private static final Logger logger = LoggerFactory.getLogger(Versions.class); - public static Version CURRENT = new Version(FBUtilities.getReleaseVersionString(), getClassPath()); - - private static URL[] getClassPath() - { - // In Java 9 the default system ClassLoader got changed from URLClassLoader to AppClassLoader which - // does not extend URLClassLoader nor does it give access to the class path array. - // Java requires the system property 'java.class.path' to be setup with the classpath seperated by : - // so this logic parses that string into the URL[] needed to build later - String cp = System.getProperty("java.class.path"); - assert cp != null && !cp.isEmpty(); - String[] split = cp.split(File.pathSeparator); - assert split.length > 0; - URL[] urls = new URL[split.length]; - try - { - for (int i = 0; i < split.length; i++) - urls[i] = Paths.get(split[i]).toUri().toURL(); - } - catch (MalformedURLException e) - { - throw new RuntimeException(e); - } - return urls; - } - - public enum Major - { - v22("2\\.2\\.([0-9]+)"), - v30("3\\.0\\.([0-9]+)"), - v3X("3\\.([1-9]|1[01])(\\.([0-9]+))?"), - v4("4\\.([0-9]+)"); - final Pattern pattern; - Major(String verify) - { - this.pattern = Pattern.compile(verify); - } - - static Major fromFull(String version) - { - if (version.isEmpty()) - throw new IllegalArgumentException(version); - switch (version.charAt(0)) - { - case '2': - if (version.startsWith("2.2")) - return v22; - throw new IllegalArgumentException(version); - case '3': - if (version.startsWith("3.0")) - return v30; - return v3X; - case '4': - return v4; - default: - throw new IllegalArgumentException(version); - } - } - - // verify that the version string is valid for this major version - boolean verify(String version) - { - return pattern.matcher(version).matches(); - } - - // sort two strings of the same major version as this enum instance - int compare(String a, String b) - { - Matcher ma = pattern.matcher(a); - Matcher mb = pattern.matcher(a); - if (!ma.matches()) throw new IllegalArgumentException(a); - if (!mb.matches()) throw new IllegalArgumentException(b); - int result = Integer.compare(Integer.parseInt(ma.group(1)), Integer.parseInt(mb.group(1))); - if (result == 0 && this == v3X && (ma.group(3) != null || mb.group(3) != null)) - { - if (ma.group(3) != null && mb.group(3) != null) - { - result = Integer.compare(Integer.parseInt(ma.group(3)), Integer.parseInt(mb.group(3))); - } - else - { - result = ma.group(3) != null ? 1 : -1; - } - } - // sort descending - return -result; - } - } - - public static class Version - { - public final Major major; - public final String version; - public final URL[] classpath; - - public Version(String version, URL[] classpath) - { - this(Major.fromFull(version), version, classpath); - } - public Version(Major major, String version, URL[] classpath) - { - this.major = major; - this.version = version; - this.classpath = classpath; - } - } - - private final Map> versions; - public Versions(Map> versions) - { - this.versions = versions; - } - - public Version get(String full) - { - return versions.get(Major.fromFull(full)) - .stream() - .filter(v -> full.equals(v.version)) - .findFirst() - .orElseThrow(() -> new RuntimeException("No version " + full + " found")); - } - - public Version getLatest(Major major) - { - return versions.get(major).stream().findFirst().orElseThrow(() -> new RuntimeException("No " + major + " versions found")); - } - - public static Versions find() - { - final String dtestJarDirectory = System.getProperty(Config.PROPERTY_PREFIX + "test.dtest_jar_path","build"); - final File sourceDirectory = new File(dtestJarDirectory); - logger.info("Looking for dtest jars in " + sourceDirectory.getAbsolutePath()); - final Pattern pattern = Pattern.compile("dtest-(?(\\d+)\\.(\\d+)(\\.\\d+)?(\\.\\d+)?)([~\\-]\\w[.\\w]*(?:\\-\\w[.\\w]*)*)?(\\+[.\\w]+)?\\.jar"); - final Map> versions = new HashMap<>(); - for (Major major : Major.values()) - versions.put(major, new ArrayList<>()); - - for (File file : sourceDirectory.listFiles()) - { - Matcher m = pattern.matcher(file.getName()); - if (!m.matches()) - continue; - String version = m.group("fullversion"); - Major major = Major.fromFull(version); - versions.get(major).add(new Version(major, version, new URL[] { toURL(file) })); - } - - for (Map.Entry> e : versions.entrySet()) - { - if (e.getValue().isEmpty()) - continue; - Collections.sort(e.getValue(), Comparator.comparing(v -> v.version, e.getKey()::compare)); - logger.info("Found " + e.getValue().stream().map(v -> v.version).collect(Collectors.joining(", "))); - } - - return new Versions(versions); - } - - public static URL toURL(File file) - { - try - { - return file.toURI().toURL(); - } - catch (MalformedURLException e) - { - throw new IllegalArgumentException(e); - } - } - -} diff --git a/test/distributed/org/apache/cassandra/distributed/api/IListen.java b/test/distributed/org/apache/cassandra/distributed/shared/RepairResult.java similarity index 72% rename from test/distributed/org/apache/cassandra/distributed/api/IListen.java rename to test/distributed/org/apache/cassandra/distributed/shared/RepairResult.java index c2e8dd6361..7be381a5f1 100644 --- a/test/distributed/org/apache/cassandra/distributed/api/IListen.java +++ b/test/distributed/org/apache/cassandra/distributed/shared/RepairResult.java @@ -16,13 +16,16 @@ * limitations under the License. */ -package org.apache.cassandra.distributed.api; +package org.apache.cassandra.distributed.shared; -public interface IListen +public class RepairResult { - public interface Cancel { void cancel(); } + public final boolean success; + public final boolean wasInconsistent; - Cancel schema(Runnable onChange); - - Cancel liveMembers(Runnable onChange); + public RepairResult(boolean success, boolean wasInconsistent) + { + this.success = success; + this.wasInconsistent = wasInconsistent; + } } diff --git a/test/distributed/org/apache/cassandra/distributed/test/BootstrapTest.java b/test/distributed/org/apache/cassandra/distributed/test/BootstrapTest.java index 0af26ea0e6..11c2f9d08f 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/BootstrapTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/BootstrapTest.java @@ -25,17 +25,21 @@ import java.util.stream.IntStream; import org.junit.Assert; import org.junit.Test; -import org.apache.cassandra.db.ConsistencyLevel; -import org.apache.cassandra.distributed.Cluster; +import org.apache.cassandra.distributed.api.ConsistencyLevel; +import org.apache.cassandra.distributed.api.ICluster; import org.apache.cassandra.distributed.api.IInstance; -import org.apache.cassandra.distributed.impl.IInvokableInstance; -import org.apache.cassandra.distributed.impl.InstanceConfig; -import org.apache.cassandra.distributed.impl.NetworkTopology; +import org.apache.cassandra.distributed.api.IInstanceConfig; +import org.apache.cassandra.distributed.api.TokenSupplier; +import org.apache.cassandra.distributed.api.IInvokableInstance; +import org.apache.cassandra.distributed.shared.Builder; +import org.apache.cassandra.distributed.shared.NetworkTopology; import static org.apache.cassandra.distributed.api.Feature.GOSSIP; import static org.apache.cassandra.distributed.api.Feature.NETWORK; +import static org.apache.cassandra.distributed.shared.DistributedTestBase.KEYSPACE; -public class BootstrapTest extends DistributedTestBase +// TODO: this test should be removed after running in-jvm dtests is set up via the shared API repository +public class BootstrapTest extends TestBaseImpl { @Test @@ -43,24 +47,22 @@ public class BootstrapTest extends DistributedTestBase { int originalNodeCount = 2; int expandedNodeCount = originalNodeCount + 1; - Cluster.Builder builder = Cluster.build(originalNodeCount) - .withTokenSupplier(Cluster.evenlyDistributedTokens(expandedNodeCount)) - .withNodeIdTopology(NetworkTopology.singleDcNetworkTopology(originalNodeCount, "dc0", "rack0")) - .withConfig(config -> config.with(NETWORK, GOSSIP)); + Builder builder = builder().withNodes(originalNodeCount) + .withTokenSupplier(TokenSupplier.evenlyDistributedTokens(expandedNodeCount)) + .withNodeIdTopology(NetworkTopology.singleDcNetworkTopology(originalNodeCount, "dc0", "rack0")) + .withConfig(config -> config.with(NETWORK, GOSSIP)); Map withBootstrap = null; Map naturally = null; - - try (Cluster cluster = builder.start()) + try (ICluster cluster = builder.withNodes(originalNodeCount).start()) { populate(cluster); - InstanceConfig config = builder.withNodeIdTopology(NetworkTopology.singleDcNetworkTopology(expandedNodeCount, "dc0", "rack0")) - .newInstanceConfig(cluster); + IInstanceConfig config = builder.withNodeIdTopology(NetworkTopology.singleDcNetworkTopology(expandedNodeCount, "dc0", "rack0")) + .newInstanceConfig(cluster); config.set("auto_bootstrap", true); - IInstance newInstance = cluster.bootstrap(config); - newInstance.startup(); + cluster.bootstrap(config).startup(); cluster.stream().forEach(instance -> { instance.nodetool("cleanup", KEYSPACE, "tbl"); @@ -69,20 +71,21 @@ public class BootstrapTest extends DistributedTestBase withBootstrap = count(cluster); } - builder = Cluster.build(expandedNodeCount) - .withTokenSupplier(Cluster.evenlyDistributedTokens(expandedNodeCount)) + builder = builder.withNodes(expandedNodeCount) + .withTokenSupplier(TokenSupplier.evenlyDistributedTokens(expandedNodeCount)) .withConfig(config -> config.with(NETWORK, GOSSIP)); - try (Cluster cluster = builder.start()) + try (ICluster cluster = builder.start()) { populate(cluster); naturally = count(cluster); } - Assert.assertEquals(withBootstrap, naturally); + for (Map.Entry e : withBootstrap.entrySet()) + Assert.assertTrue(e.getValue() >= naturally.get(e.getKey())); } - public void populate(Cluster cluster) + public void populate(ICluster cluster) { cluster.schemaChange("CREATE KEYSPACE " + KEYSPACE + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': " + 3 + "};"); cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck))"); @@ -93,12 +96,11 @@ public class BootstrapTest extends DistributedTestBase i, i, i); } - public Map count(Cluster cluster) + public Map count(ICluster cluster) { return IntStream.rangeClosed(1, cluster.size()) .boxed() .collect(Collectors.toMap(nodeId -> nodeId, nodeId -> (Long) cluster.get(nodeId).executeInternal("SELECT count(*) FROM " + KEYSPACE + ".tbl")[0][0])); } - -} +} \ No newline at end of file diff --git a/test/distributed/org/apache/cassandra/distributed/test/CasWriteTest.java b/test/distributed/org/apache/cassandra/distributed/test/CasWriteTest.java index 7e7c629654..a5d7e72f47 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/CasWriteTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/CasWriteTest.java @@ -43,9 +43,10 @@ import org.junit.rules.ExpectedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.cassandra.db.ConsistencyLevel; import org.apache.cassandra.distributed.Cluster; -import org.apache.cassandra.distributed.impl.InstanceClassLoader; +import org.apache.cassandra.distributed.api.ConsistencyLevel; +import org.apache.cassandra.distributed.api.ICluster; +import org.apache.cassandra.distributed.shared.InstanceClassLoader; import org.apache.cassandra.exceptions.CasWriteTimeoutException; import org.apache.cassandra.exceptions.CasWriteUnknownResultException; import org.apache.cassandra.net.Verb; @@ -54,12 +55,13 @@ import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.fail; +import static org.apache.cassandra.distributed.shared.AssertUtils.*; -public class CasWriteTest extends DistributedTestBase +// TODO: this test should be removed after running in-jvm dtests is set up via the shared API repository +public class CasWriteTest extends TestBaseImpl { // Sharing the same cluster to boost test speed. Using a pkGen to make sure queries has distinct pk value for paxos instances. - private static Cluster cluster; + private static ICluster cluster; private static final AtomicInteger pkGen = new AtomicInteger(1_000); // preserve any pk values less than 1000 for manual queries. private static final Logger logger = LoggerFactory.getLogger(CasWriteTest.class); @@ -69,12 +71,12 @@ public class CasWriteTest extends DistributedTestBase @BeforeClass public static void setupCluster() throws Throwable { - cluster = init(Cluster.create(3)); + cluster = init(Cluster.build().withNodes(3).start()); cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck))"); } @AfterClass - public static void close() + public static void close() throws Exception { cluster.close(); cluster = null; @@ -106,7 +108,7 @@ public class CasWriteTest extends DistributedTestBase public void testCasWriteTimeoutAtPreparePhase_ReqLost() { expectCasWriteTimeout(); - cluster.verbs(Verb.PAXOS_PREPARE_REQ).from(1).to(2, 3).drop().on(); // drop the internode messages to acceptors + cluster.filters().verbs(Verb.PAXOS_PREPARE_REQ.id).from(1).to(2, 3).drop().on(); // drop the internode messages to acceptors cluster.coordinator(1).execute(mkUniqueCasInsertQuery(1), ConsistencyLevel.QUORUM); } @@ -114,7 +116,7 @@ public class CasWriteTest extends DistributedTestBase public void testCasWriteTimeoutAtPreparePhase_RspLost() { expectCasWriteTimeout(); - cluster.verbs(Verb.PAXOS_PREPARE_RSP).from(2, 3).to(1).drop().on(); // drop the internode messages to acceptors + cluster.filters().verbs(Verb.PAXOS_PREPARE_RSP.id).from(2, 3).to(1).drop().on(); // drop the internode messages to acceptors cluster.coordinator(1).execute(mkUniqueCasInsertQuery(1), ConsistencyLevel.QUORUM); } @@ -122,7 +124,7 @@ public class CasWriteTest extends DistributedTestBase public void testCasWriteTimeoutAtProposePhase_ReqLost() { expectCasWriteTimeout(); - cluster.verbs(Verb.PAXOS_PROPOSE_REQ).from(1).to(2, 3).drop().on(); + cluster.filters().verbs(Verb.PAXOS_PROPOSE_REQ.id).from(1).to(2, 3).drop().on(); cluster.coordinator(1).execute(mkUniqueCasInsertQuery(1), ConsistencyLevel.QUORUM); } @@ -130,7 +132,7 @@ public class CasWriteTest extends DistributedTestBase public void testCasWriteTimeoutAtProposePhase_RspLost() { expectCasWriteTimeout(); - cluster.verbs(Verb.PAXOS_PROPOSE_RSP).from(2, 3).to(1).drop().on(); + cluster.filters().verbs(Verb.PAXOS_PROPOSE_RSP.id).from(2, 3).to(1).drop().on(); cluster.coordinator(1).execute(mkUniqueCasInsertQuery(1), ConsistencyLevel.QUORUM); } @@ -138,7 +140,7 @@ public class CasWriteTest extends DistributedTestBase public void testCasWriteTimeoutAtCommitPhase_ReqLost() { expectCasWriteTimeout(); - cluster.verbs(Verb.PAXOS_COMMIT_REQ).from(1).to(2, 3).drop().on(); + cluster.filters().verbs(Verb.PAXOS_COMMIT_REQ.id).from(1).to(2, 3).drop().on(); cluster.coordinator(1).execute(mkUniqueCasInsertQuery(1), ConsistencyLevel.QUORUM); } @@ -146,7 +148,7 @@ public class CasWriteTest extends DistributedTestBase public void testCasWriteTimeoutAtCommitPhase_RspLost() { expectCasWriteTimeout(); - cluster.verbs(Verb.PAXOS_COMMIT_RSP).from(2, 3).to(1).drop().on(); + cluster.filters().verbs(Verb.PAXOS_COMMIT_RSP.id).from(2, 3).to(1).drop().on(); cluster.coordinator(1).execute(mkUniqueCasInsertQuery(1), ConsistencyLevel.QUORUM); } @@ -159,8 +161,8 @@ public class CasWriteTest extends DistributedTestBase Arrays.asList(1, 3), c -> { c.filters().reset(); - c.verbs(Verb.PAXOS_PREPARE_REQ).from(1).to(3).drop(); - c.verbs(Verb.PAXOS_PROPOSE_REQ).from(1).to(2).drop(); + c.filters().verbs(Verb.PAXOS_PREPARE_REQ.id).from(1).to(3).drop(); + c.filters().verbs(Verb.PAXOS_PROPOSE_REQ.id).from(1).to(2).drop(); }, failure -> failure.get() != null && @@ -172,7 +174,7 @@ public class CasWriteTest extends DistributedTestBase private void testWithContention(int testUid, List contendingNodes, - Consumer setupForEachRound, + Consumer setupForEachRound, Function, Boolean> expectedException, String assertHintMessage) throws InterruptedException { diff --git a/test/distributed/org/apache/cassandra/distributed/test/DistributedRepairUtils.java b/test/distributed/org/apache/cassandra/distributed/test/DistributedRepairUtils.java index 7f162e1465..023d02ce1c 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/DistributedRepairUtils.java +++ b/test/distributed/org/apache/cassandra/distributed/test/DistributedRepairUtils.java @@ -26,12 +26,12 @@ import com.google.common.collect.ImmutableSet; import org.apache.commons.lang3.ArrayUtils; import org.junit.Assert; -import org.apache.cassandra.db.ConsistencyLevel; +import org.apache.cassandra.distributed.api.ConsistencyLevel; +import org.apache.cassandra.distributed.api.IInvokableInstance; import org.apache.cassandra.distributed.api.NodeToolResult; import org.apache.cassandra.distributed.api.QueryResult; import org.apache.cassandra.distributed.api.Row; import org.apache.cassandra.distributed.impl.AbstractCluster; -import org.apache.cassandra.distributed.impl.IInvokableInstance; import org.apache.cassandra.metrics.StorageMetrics; import static org.apache.cassandra.utils.Retry.retryWithBackoffBlocking; diff --git a/test/distributed/org/apache/cassandra/distributed/test/DistributedTestBase.java b/test/distributed/org/apache/cassandra/distributed/test/DistributedTestBase.java deleted file mode 100644 index f89f8f491c..0000000000 --- a/test/distributed/org/apache/cassandra/distributed/test/DistributedTestBase.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.cassandra.distributed.test; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - -import com.google.common.collect.Iterators; -import org.junit.After; -import org.junit.Assert; -import org.junit.BeforeClass; - -import com.datastax.driver.core.ResultSet; -import org.apache.cassandra.config.DatabaseDescriptor; -import org.apache.cassandra.distributed.impl.AbstractCluster; -import org.apache.cassandra.distributed.impl.IsolatedExecutor; -import org.apache.cassandra.distributed.impl.RowUtil; - -public class DistributedTestBase -{ - @After - public void afterEach() - { - System.runFinalization(); - System.gc(); - } - - public static String KEYSPACE = "distributed_test_keyspace"; - - public static void nativeLibraryWorkaround() - { - // Disable the Netty tcnative library otherwise the io.netty.internal.tcnative.CertificateCallbackTask, - // CertificateVerifierTask, SSLPrivateKeyMethodDecryptTask, SSLPrivateKeyMethodSignTask, - // SSLPrivateKeyMethodTask, and SSLTask hold a gcroot against the InstanceClassLoader. - System.setProperty("cassandra.disable_tcactive_openssl", "true"); - System.setProperty("io.netty.transport.noNative", "true"); - } - - public static void processReaperWorkaround() - { - // Make sure the 'process reaper' thread is initially created under the main classloader, - // otherwise it gets created with the contextClassLoader pointing to an InstanceClassLoader - // which prevents it from being garbage collected. - IsolatedExecutor.ThrowingRunnable.toRunnable(() -> new ProcessBuilder().command("true").start().waitFor()).run(); - } - - @BeforeClass - public static void setup() - { - System.setProperty("cassandra.ring_delay_ms", Integer.toString(10 * 1000)); - System.setProperty("org.apache.cassandra.disable_mbean_registration", "true"); - nativeLibraryWorkaround(); - processReaperWorkaround(); - DatabaseDescriptor.clientInitialization(); - } - - static String withKeyspace(String replaceIn) - { - return String.format(replaceIn, KEYSPACE); - } - - protected static > C init(C cluster) - { - return init(cluster, cluster.size()); - } - - protected static > C init(C cluster, int replicationFactor) - { - cluster.schemaChange("CREATE KEYSPACE " + KEYSPACE + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': " + replicationFactor + "};"); - return cluster; - } - - public static void assertRows(ResultSet actual,Object[]... expected) - { - assertRows(RowUtil.toObjects(actual), expected); - } - - public static void assertRows(Object[][] actual, Object[]... expected) - { - Assert.assertEquals(rowsNotEqualErrorMessage(actual, expected), - expected.length, actual.length); - - for (int i = 0; i < expected.length; i++) - { - Object[] expectedRow = expected[i]; - Object[] actualRow = actual[i]; - Assert.assertTrue(rowsNotEqualErrorMessage(actual, expected), - Arrays.equals(expectedRow, actualRow)); - } - } - - public static void assertRow(Object[] actual, Object... expected) - { - Assert.assertTrue(rowNotEqualErrorMessage(actual, expected), - Arrays.equals(actual, expected)); - } - - public static void assertRows(Iterator actual, Iterator expected) - { - while (actual.hasNext() && expected.hasNext()) - assertRow(actual.next(), expected.next()); - - Assert.assertEquals("Resultsets have different sizes", actual.hasNext(), expected.hasNext()); - } - - public static void assertRows(Iterator actual, Object[]... expected) - { - assertRows(actual, Iterators.forArray(expected)); - } - - public static String rowNotEqualErrorMessage(Object[] actual, Object[] expected) - { - return String.format("Expected: %s\nActual:%s\n", - Arrays.toString(expected), - Arrays.toString(actual)); - } - - public static String rowsNotEqualErrorMessage(Object[][] actual, Object[][] expected) - { - return String.format("Expected: %s\nActual: %s\n", - rowsToString(expected), - rowsToString(actual)); - } - - public static String rowsToString(Object[][] rows) - { - StringBuilder builder = new StringBuilder(); - builder.append("["); - boolean isFirst = true; - for (Object[] row : rows) - { - if (isFirst) - isFirst = false; - else - builder.append(","); - builder.append(Arrays.toString(row)); - } - builder.append("]"); - return builder.toString(); - } - - public static Object[][] toObjectArray(Iterator iter) - { - List res = new ArrayList<>(); - while (iter.hasNext()) - res.add(iter.next()); - - return res.toArray(new Object[res.size()][]); - } - - public static Object[] row(Object... expected) - { - return expected; - } -} diff --git a/test/distributed/org/apache/cassandra/distributed/impl/ExecUtil.java b/test/distributed/org/apache/cassandra/distributed/test/ExecUtil.java similarity index 96% rename from test/distributed/org/apache/cassandra/distributed/impl/ExecUtil.java rename to test/distributed/org/apache/cassandra/distributed/test/ExecUtil.java index b907626ae8..b9fbd5cbb0 100644 --- a/test/distributed/org/apache/cassandra/distributed/impl/ExecUtil.java +++ b/test/distributed/org/apache/cassandra/distributed/test/ExecUtil.java @@ -16,7 +16,7 @@ * limitations under the License. */ -package org.apache.cassandra.distributed.impl; +package org.apache.cassandra.distributed.test; import java.io.Serializable; diff --git a/test/distributed/org/apache/cassandra/distributed/test/FailingRepairTest.java b/test/distributed/org/apache/cassandra/distributed/test/FailingRepairTest.java index 25e299c0d6..bad6d87c8f 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/FailingRepairTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/FailingRepairTest.java @@ -45,7 +45,8 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import org.apache.cassandra.db.ColumnFamilyStore; -import org.apache.cassandra.db.ConsistencyLevel; +import org.apache.cassandra.distributed.Cluster; +import org.apache.cassandra.distributed.api.ConsistencyLevel; import org.apache.cassandra.db.DataRange; import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.db.PartitionPosition; @@ -54,10 +55,10 @@ import org.apache.cassandra.db.rows.UnfilteredRowIterator; import org.apache.cassandra.dht.AbstractBounds; import org.apache.cassandra.dht.Range; import org.apache.cassandra.dht.Token; -import org.apache.cassandra.distributed.Cluster; import org.apache.cassandra.distributed.api.Feature; +import org.apache.cassandra.distributed.api.ICluster; import org.apache.cassandra.distributed.api.IIsolatedExecutor.SerializableRunnable; -import org.apache.cassandra.distributed.impl.IInvokableInstance; +import org.apache.cassandra.distributed.api.IInvokableInstance; import org.apache.cassandra.distributed.impl.InstanceKiller; import org.apache.cassandra.io.sstable.CorruptSSTableException; import org.apache.cassandra.io.sstable.ISSTableScanner; @@ -73,9 +74,9 @@ import org.apache.cassandra.service.ActiveRepairService.ParentRepairStatus; import org.apache.cassandra.service.StorageService; @RunWith(Parameterized.class) -public class FailingRepairTest extends DistributedTestBase implements Serializable +public class FailingRepairTest extends TestBaseImpl implements Serializable { - private static Cluster CLUSTER; + private static ICluster CLUSTER; private final Verb messageType; private final RepairParallelism parallelism; @@ -136,15 +137,16 @@ public class FailingRepairTest extends DistributedTestBase implements Serializab { // streaming requires networking ATM // streaming also requires gossip or isn't setup properly - CLUSTER = init(Cluster.build(2) - .withConfig(c -> c.with(Feature.NETWORK) - .with(Feature.GOSSIP) - .set("disk_failure_policy", "die")) - .start()); + CLUSTER = init(Cluster.build() + .withNodes(2) + .withConfig(c -> c.with(Feature.NETWORK) + .with(Feature.GOSSIP) + .set("disk_failure_policy", "die")) + .start()); } @AfterClass - public static void teardownCluster() + public static void teardownCluster() throws Exception { if (CLUSTER != null) CLUSTER.close(); @@ -154,7 +156,7 @@ public class FailingRepairTest extends DistributedTestBase implements Serializab public void cleanupState() { for (int i = 1; i <= CLUSTER.size(); i++) - CLUSTER.get(i).runOnInstance(() -> InstanceKiller.clear()); + CLUSTER.get(i).runOnInstance(InstanceKiller::clear); } @Test(timeout = 10 * 60 * 1000) diff --git a/test/distributed/org/apache/cassandra/distributed/test/GossipSettlesTest.java b/test/distributed/org/apache/cassandra/distributed/test/GossipSettlesTest.java index 5f1263af1d..509fe6f006 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/GossipSettlesTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/GossipSettlesTest.java @@ -18,23 +18,25 @@ package org.apache.cassandra.distributed.test; -import java.io.IOException; - import org.junit.Test; -import org.apache.cassandra.distributed.Cluster; +import org.apache.cassandra.distributed.api.ICluster; import static org.apache.cassandra.distributed.api.Feature.GOSSIP; import static org.apache.cassandra.distributed.api.Feature.NETWORK; -public class GossipSettlesTest extends DistributedTestBase +// TODO: this test should be removed after running in-jvm dtests is set up via the shared API repository +public class GossipSettlesTest extends TestBaseImpl { @Test - public void testGossipSettles() throws IOException + public void testGossipSettles() throws Throwable { - // Use withSubnet(1) to prove seed provider is set correctly - without the fix to pass a seed provider, this test fails - try (Cluster cluster = Cluster.build(3).withConfig(config -> config.with(GOSSIP).with(NETWORK)).withSubnet(1).start()) + /* Use withSubnet(1) to prove seed provider is set correctly - without the fix to pass a seed provider, this test fails */ + try (ICluster cluster = builder().withNodes(3) + .withConfig(config -> config.with(GOSSIP).with(NETWORK)) + .withSubnet(1) + .start()) { } } diff --git a/test/distributed/org/apache/cassandra/distributed/test/LargeColumnTest.java b/test/distributed/org/apache/cassandra/distributed/test/LargeColumnTest.java index 0c28d38ffd..0a81359dcf 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/LargeColumnTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/LargeColumnTest.java @@ -20,21 +20,22 @@ package org.apache.cassandra.distributed.test; import java.util.Random; import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.cassandra.db.ConsistencyLevel; -import org.apache.cassandra.distributed.Cluster; +import org.apache.cassandra.distributed.api.ConsistencyLevel; +import org.apache.cassandra.distributed.api.ICluster; import static java.util.concurrent.TimeUnit.SECONDS; -public class LargeColumnTest extends DistributedTestBase +// TODO: this test should be removed after running in-jvm dtests is set up via the shared API repository +public class LargeColumnTest extends TestBaseImpl { private static final Logger logger = LoggerFactory.getLogger(LargeColumnTest.class); + private static String str(int length, Random random, long seed) { random.setSeed(seed); @@ -63,23 +64,24 @@ public class LargeColumnTest extends DistributedTestBase long seed = ThreadLocalRandom.current().nextLong(); logger.info("Using seed {}", seed); - try (Cluster cluster = init(Cluster.build(nodes) - .withConfig(config -> - config.set("commitlog_segment_size_in_mb", (columnSize * 3) >> 20) - .set("internode_application_send_queue_reserve_endpoint_capacity_in_bytes", columnSize * 2) - .set("internode_application_send_queue_reserve_global_capacity_in_bytes", columnSize * 3) - .set("write_request_timeout_in_ms", SECONDS.toMillis(30L)) - .set("read_request_timeout_in_ms", SECONDS.toMillis(30L)) - .set("memtable_heap_space_in_mb", 1024) - ) - .start())) + try (ICluster cluster = init(builder() + .withNodes(nodes) + .withConfig(config -> + config.set("commitlog_segment_size_in_mb", (columnSize * 3) >> 20) + .set("internode_application_send_queue_reserve_endpoint_capacity_in_bytes", columnSize * 2) + .set("internode_application_send_queue_reserve_global_capacity_in_bytes", columnSize * 3) + .set("write_request_timeout_in_ms", SECONDS.toMillis(30L)) + .set("read_request_timeout_in_ms", SECONDS.toMillis(30L)) + .set("memtable_heap_space_in_mb", 1024) + ) + .start())) { cluster.schemaChange(String.format("CREATE TABLE %s.cf (k int, c text, PRIMARY KEY (k))", KEYSPACE)); - for (int i = 0 ; i < rowCount ; ++i) + for (int i = 0; i < rowCount; ++i) cluster.coordinator(1).execute(String.format("INSERT INTO %s.cf (k, c) VALUES (?, ?);", KEYSPACE), ConsistencyLevel.ALL, i, str(columnSize, random, seed | i)); - for (int i = 0 ; i < rowCount ; ++i) + for (int i = 0; i < rowCount; ++i) { Object[][] results = cluster.coordinator(1).execute(String.format("SELECT k, c FROM %s.cf WHERE k = ?;", KEYSPACE), ConsistencyLevel.ALL, i); Assert.assertTrue(str(columnSize, random, seed | i).equals(results[0][1])); @@ -92,5 +94,4 @@ public class LargeColumnTest extends DistributedTestBase { testLargeColumns(2, 16 << 20, 5); } - -} +} \ No newline at end of file diff --git a/test/distributed/org/apache/cassandra/distributed/test/MessageFiltersTest.java b/test/distributed/org/apache/cassandra/distributed/test/MessageFiltersTest.java index 814e2296d0..bd09891aa0 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/MessageFiltersTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/MessageFiltersTest.java @@ -18,6 +18,7 @@ package org.apache.cassandra.distributed.test; +import java.net.InetSocketAddress; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -29,20 +30,22 @@ import com.google.common.collect.Sets; import org.junit.Assert; import org.junit.Test; -import org.apache.cassandra.db.ConsistencyLevel; import org.apache.cassandra.distributed.Cluster; +import org.apache.cassandra.distributed.api.ConsistencyLevel; +import org.apache.cassandra.distributed.api.ICluster; +import org.apache.cassandra.distributed.api.IInvokableInstance; import org.apache.cassandra.distributed.api.IIsolatedExecutor; import org.apache.cassandra.distributed.api.IMessage; import org.apache.cassandra.distributed.api.IMessageFilters; import org.apache.cassandra.distributed.impl.Instance; -import org.apache.cassandra.distributed.impl.MessageFilters; +import org.apache.cassandra.distributed.shared.MessageFilters; import org.apache.cassandra.locator.InetAddressAndPort; import org.apache.cassandra.net.Message; import org.apache.cassandra.net.MessagingService; import org.apache.cassandra.net.NoPayload; import org.apache.cassandra.net.Verb; -public class MessageFiltersTest extends DistributedTestBase +public class MessageFiltersTest extends TestBaseImpl { @Test public void simpleInboundFiltersTest() @@ -73,7 +76,7 @@ public class MessageFiltersTest extends DistributedTestBase String MSG2 = "msg2"; MessageFilters filters = new MessageFilters(); - Permit permit = inbound ? (from, to, msg) -> filters.permitInbound(from, to, msg) : (from, to, msg) -> filters.permitOutbound(from, to, msg); + Permit permit = inbound ? filters::permitInbound : filters::permitOutbound; IMessageFilters.Filter filter = filters.allVerbs().inbound(inbound).from(1).drop(); Assert.assertFalse(permit.test(i1, i2, msg(VERB1, MSG1))); @@ -136,7 +139,11 @@ public class MessageFiltersTest extends DistributedTestBase public byte[] bytes() { return msg.getBytes(); } public int id() { return 0; } public int version() { return 0; } - public InetAddressAndPort from() { return null; } + public InetSocketAddress from() { return null; } + public int fromPort() + { + return 0; + } }; } @@ -146,7 +153,7 @@ public class MessageFiltersTest extends DistributedTestBase String read = "SELECT * FROM " + KEYSPACE + ".tbl"; String write = "INSERT INTO " + KEYSPACE + ".tbl (pk, ck, v) VALUES (1, 1, 1)"; - try (Cluster cluster = Cluster.create(2)) + try (ICluster cluster = builder().withNodes(2).start()) { cluster.schemaChange("CREATE KEYSPACE " + KEYSPACE + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': " + cluster.size() + "};"); cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck))"); @@ -176,7 +183,7 @@ public class MessageFiltersTest extends DistributedTestBase String read = "SELECT * FROM " + KEYSPACE + ".tbl"; String write = "INSERT INTO " + KEYSPACE + ".tbl (pk, ck, v) VALUES (1, 1, 1)"; - try (Cluster cluster = Cluster.create(2)) + try (ICluster cluster = builder().withNodes(2).start()) { cluster.schemaChange("CREATE KEYSPACE " + KEYSPACE + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': " + cluster.size() + "};"); cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck))"); @@ -224,7 +231,8 @@ public class MessageFiltersTest extends DistributedTestBase { try (Cluster cluster = Cluster.create(2)) { - InetAddressAndPort other = cluster.get(2).broadcastAddressAndPort(); + InetAddressAndPort other = InetAddressAndPort.getByAddressOverrideDefaults(cluster.get(2).broadcastAddress().getAddress(), + cluster.get(2).broadcastAddress().getPort()); CountDownLatch waitForIt = new CountDownLatch(1); Set outboundMessagesSeen = new HashSet<>(); Set inboundMessagesSeen = new HashSet<>(); diff --git a/test/distributed/org/apache/cassandra/distributed/test/MessageForwardingTest.java b/test/distributed/org/apache/cassandra/distributed/test/MessageForwardingTest.java index 17bd6e1d92..153d7de706 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/MessageForwardingTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/MessageForwardingTest.java @@ -32,44 +32,44 @@ import java.util.stream.Stream; import org.junit.Assert; import org.junit.Test; -import org.apache.cassandra.db.ConsistencyLevel; +import org.apache.cassandra.distributed.api.ConsistencyLevel; import org.apache.cassandra.distributed.Cluster; import org.apache.cassandra.distributed.impl.IsolatedExecutor; import org.apache.cassandra.distributed.impl.TracingUtil; import org.apache.cassandra.utils.UUIDGen; -public class MessageForwardingTest extends DistributedTestBase +public class MessageForwardingTest extends TestBaseImpl { @Test public void mutationsForwardedToAllReplicasTest() { String originalTraceTimeout = TracingUtil.setWaitForTracingEventTimeoutSecs("1"); final int numInserts = 100; - Map forwardFromCounts = new HashMap<>(); - Map commitCounts = new HashMap<>(); + Map forwardFromCounts = new HashMap<>(); + Map commitCounts = new HashMap<>(); - try (Cluster cluster = init(Cluster.build() - .withDC("dc0", 1) - .withDC("dc1", 3) - .start())) + try (Cluster cluster = (Cluster) init(builder() + .withDC("dc0", 1) + .withDC("dc1", 3) + .start())) { cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v text, PRIMARY KEY (pk, ck))"); - cluster.forEach(instance -> commitCounts.put(instance.broadcastAddressAndPort().address, 0)); + cluster.forEach(instance -> commitCounts.put(instance.broadcastAddress().getAddress(), 0)); final UUID sessionId = UUIDGen.getTimeUUID(); - Stream> inserts = IntStream.range(0, numInserts).mapToObj((idx) -> - cluster.coordinator(1).asyncExecuteWithTracing(sessionId, - "INSERT INTO " + KEYSPACE + ".tbl(pk,ck,v) VALUES (1, 1, 'x')", - ConsistencyLevel.ALL) - ); + Stream> inserts = IntStream.range(0, numInserts).mapToObj((idx) -> { + return cluster.coordinator(1).asyncExecuteWithTracing(sessionId, + "INSERT INTO " + KEYSPACE + ".tbl(pk,ck,v) VALUES (1, 1, 'x')", + ConsistencyLevel.ALL); + }); // Wait for each of the futures to complete before checking the traces, don't care // about the result so //noinspection ResultOfMethodCallIgnored inserts.map(IsolatedExecutor::waitOn).collect(Collectors.toList()); - cluster.stream("dc1").forEach(instance -> forwardFromCounts.put(instance.broadcastAddressAndPort().address, 0)); - cluster.forEach(instance -> commitCounts.put(instance.broadcastAddressAndPort().address, 0)); + cluster.stream("dc1").forEach(instance -> forwardFromCounts.put(instance.broadcastAddress().getAddress(), 0)); + cluster.forEach(instance -> commitCounts.put(instance.broadcastAddress().getAddress(), 0)); List traces = TracingUtil.getTrace(cluster, sessionId, ConsistencyLevel.ALL); traces.forEach(traceEntry -> { if (traceEntry.activity.contains("Appending to commitlog")) @@ -100,4 +100,4 @@ public class MessageForwardingTest extends DistributedTestBase TracingUtil.setWaitForTracingEventTimeoutSecs(originalTraceTimeout); } } -} +} \ No newline at end of file diff --git a/test/distributed/org/apache/cassandra/distributed/test/NativeProtocolTest.java b/test/distributed/org/apache/cassandra/distributed/test/NativeProtocolTest.java index 45d9840f81..0905b92f53 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/NativeProtocolTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/NativeProtocolTest.java @@ -18,50 +18,53 @@ package org.apache.cassandra.distributed.test; +import org.apache.cassandra.distributed.impl.RowUtil; +import org.junit.Assert; +import org.junit.Test; + import com.datastax.driver.core.ConsistencyLevel; import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.Session; import com.datastax.driver.core.SimpleStatement; import com.datastax.driver.core.Statement; -import org.apache.cassandra.distributed.Cluster; -import org.apache.cassandra.distributed.impl.RowUtil; - -import org.junit.Assert; -import org.junit.Test; - -import java.util.Iterator; +import org.apache.cassandra.distributed.api.ICluster; import static org.apache.cassandra.distributed.api.Feature.GOSSIP; import static org.apache.cassandra.distributed.api.Feature.NATIVE_PROTOCOL; import static org.apache.cassandra.distributed.api.Feature.NETWORK; +import static org.apache.cassandra.distributed.shared.AssertUtils.*; -public class NativeProtocolTest extends DistributedTestBase +// TODO: this test should be removed after running in-jvm dtests is set up via the shared API repository +public class NativeProtocolTest extends TestBaseImpl { @Test public void withClientRequests() throws Throwable { - try (Cluster ignored = init(Cluster.create(3, - config -> config.with(GOSSIP, NETWORK, NATIVE_PROTOCOL)))) + try (ICluster ignored = init(builder().withNodes(3) + .withConfig(config -> config.with(GOSSIP, NETWORK, NATIVE_PROTOCOL)) + .start())) { - final com.datastax.driver.core.Cluster cluster = com.datastax.driver.core.Cluster.builder().addContactPoint("127.0.0.1").build(); - Session session = cluster.connect(); - session.execute("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck));"); - session.execute("INSERT INTO " + KEYSPACE + ".tbl (pk, ck, v) values (1,1,1);"); - Statement select = new SimpleStatement("select * from " + KEYSPACE + ".tbl;").setConsistencyLevel(ConsistencyLevel.ALL); - final ResultSet resultSet = session.execute(select); - assertRows(resultSet, row(1, 1, 1)); - Assert.assertEquals(3, cluster.getMetadata().getAllHosts().size()); - session.close(); - cluster.close(); + + try (com.datastax.driver.core.Cluster cluster = com.datastax.driver.core.Cluster.builder().addContactPoint("127.0.0.1").build(); + Session session = cluster.connect()) + { + session.execute("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck));"); + session.execute("INSERT INTO " + KEYSPACE + ".tbl (pk, ck, v) values (1,1,1);"); + Statement select = new SimpleStatement("select * from " + KEYSPACE + ".tbl;").setConsistencyLevel(ConsistencyLevel.ALL); + final ResultSet resultSet = session.execute(select); + assertRows(RowUtil.toObjects(resultSet), row(1, 1, 1)); + Assert.assertEquals(3, cluster.getMetadata().getAllHosts().size()); + } } } @Test public void withCounters() throws Throwable { - try (Cluster dtCluster = init(Cluster.create(3, - config -> config.with(GOSSIP, NETWORK, NATIVE_PROTOCOL)))) + try (ICluster ignored = init(builder().withNodes(3) + .withConfig(config -> config.with(GOSSIP, NETWORK, NATIVE_PROTOCOL)) + .start())) { final com.datastax.driver.core.Cluster cluster = com.datastax.driver.core.Cluster.builder().addContactPoint("127.0.0.1").build(); Session session = cluster.connect(); @@ -69,7 +72,7 @@ public class NativeProtocolTest extends DistributedTestBase session.execute("UPDATE " + KEYSPACE + ".tbl set ck = ck + 10 where pk = 1;"); Statement select = new SimpleStatement("select * from " + KEYSPACE + ".tbl;").setConsistencyLevel(ConsistencyLevel.ALL); final ResultSet resultSet = session.execute(select); - assertRows(resultSet, row(1, 10L)); + assertRows(RowUtil.toObjects(resultSet), row(1, 10L)); Assert.assertEquals(3, cluster.getMetadata().getAllHosts().size()); session.close(); cluster.close(); diff --git a/test/distributed/org/apache/cassandra/distributed/test/NetworkTopologyTest.java b/test/distributed/org/apache/cassandra/distributed/test/NetworkTopologyTest.java index a9c2cee0d6..8230fd5e54 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/NetworkTopologyTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/NetworkTopologyTest.java @@ -26,22 +26,23 @@ import java.util.stream.Stream; import org.junit.Assert; import org.junit.Test; -import org.apache.cassandra.distributed.Cluster; +import org.apache.cassandra.distributed.api.ICluster; import org.apache.cassandra.distributed.api.IInstance; -import org.apache.cassandra.distributed.impl.NetworkTopology; -import org.apache.cassandra.utils.Pair; +import org.apache.cassandra.distributed.api.IInvokableInstance; +import org.apache.cassandra.distributed.shared.NetworkTopology; -public class NetworkTopologyTest extends DistributedTestBase +// TODO: this test should be removed after running in-jvm dtests is set up via the shared API repository +public class NetworkTopologyTest extends TestBaseImpl { @Test public void namedDcTest() throws Throwable { - try (Cluster cluster = Cluster.build() - .withNodeIdTopology(Collections.singletonMap(1, NetworkTopology.dcAndRack("somewhere", "rack0"))) - .withRack("elsewhere", "firstrack", 1) - .withRack("elsewhere", "secondrack", 2) - .withDC("nearthere", 4) - .start()) + try (ICluster cluster = builder() + .withNodeIdTopology(Collections.singletonMap(1, NetworkTopology.dcAndRack("somewhere", "rack0"))) + .withRack("elsewhere", "firstrack", 1) + .withRack("elsewhere", "secondrack", 2) + .withDC("nearthere", 4) + .start()) { Assert.assertEquals(1, cluster.stream("somewhere").count()); Assert.assertEquals(1, cluster.stream("elsewhere", "firstrack").count()); @@ -61,9 +62,8 @@ public class NetworkTopologyTest extends DistributedTestBase public void automaticNamedDcTest() throws Throwable { - try (Cluster cluster = Cluster.build() - .withRacks(2, 1, 3) - .start()) + try (ICluster cluster = builder().withRacks(2, 1, 3) + .start()) { Assert.assertEquals(6, cluster.stream().count()); Assert.assertEquals(3, cluster.stream("datacenter1").count()); @@ -74,27 +74,25 @@ public class NetworkTopologyTest extends DistributedTestBase @Test(expected = IllegalStateException.class) public void noCountsAfterNamingDCsTest() { - Cluster.build() - .withDC("nameddc", 1) - .withDCs(1); + builder().withDC("nameddc", 1) + .withDCs(1); } @Test(expected = IllegalStateException.class) public void mustProvideNodeCountBeforeWithDCsTest() { - Cluster.build() - .withDCs(1); + builder().withDCs(1); } @Test(expected = IllegalStateException.class) public void noEmptyNodeIdTopologyTest() { - Cluster.build().withNodeIdTopology(Collections.emptyMap()); + builder().withNodeIdTopology(Collections.emptyMap()); } @Test(expected = IllegalStateException.class) public void noHolesInNodeIdTopologyTest() { - Cluster.build().withNodeIdTopology(Collections.singletonMap(2, NetworkTopology.dcAndRack("doomed", "rack"))); + builder().withNodeIdTopology(Collections.singletonMap(2, NetworkTopology.dcAndRack("doomed", "rack"))); } -} +} \ No newline at end of file diff --git a/test/distributed/org/apache/cassandra/distributed/test/NodeToolTest.java b/test/distributed/org/apache/cassandra/distributed/test/NodeToolTest.java index e209d1d413..1a1bdc797a 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/NodeToolTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/NodeToolTest.java @@ -20,16 +20,16 @@ package org.apache.cassandra.distributed.test; import org.junit.Test; -import org.apache.cassandra.distributed.Cluster; +import org.apache.cassandra.distributed.api.ICluster; import static org.junit.Assert.assertEquals; -public class NodeToolTest extends DistributedTestBase +public class NodeToolTest extends TestBaseImpl { @Test public void test() throws Throwable { - try (Cluster cluster = init(Cluster.create(1))) + try (ICluster cluster = init(builder().withNodes(1).start())) { assertEquals(0, cluster.get(1).nodetool("help")); assertEquals(0, cluster.get(1).nodetool("flush")); diff --git a/test/distributed/org/apache/cassandra/distributed/test/PreviewRepairTest.java b/test/distributed/org/apache/cassandra/distributed/test/PreviewRepairTest.java index c712948bf2..30c8f25a24 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/PreviewRepairTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/PreviewRepairTest.java @@ -34,23 +34,23 @@ import com.google.common.collect.ImmutableList; import org.junit.Test; import org.apache.cassandra.db.ColumnFamilyStore; -import org.apache.cassandra.db.ConsistencyLevel; import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.db.compaction.CompactionManager; import org.apache.cassandra.dht.Range; import org.apache.cassandra.dht.Token; import org.apache.cassandra.distributed.Cluster; +import org.apache.cassandra.distributed.api.ConsistencyLevel; import org.apache.cassandra.distributed.api.ICoordinator; import org.apache.cassandra.distributed.api.IIsolatedExecutor; import org.apache.cassandra.distributed.api.IMessage; import org.apache.cassandra.distributed.api.IMessageFilters; +import org.apache.cassandra.distributed.shared.RepairResult; import org.apache.cassandra.net.Verb; import org.apache.cassandra.repair.RepairParallelism; import org.apache.cassandra.repair.messages.RepairOption; import org.apache.cassandra.service.StorageService; import org.apache.cassandra.streaming.PreviewKind; import org.apache.cassandra.utils.FBUtilities; -import org.apache.cassandra.utils.Pair; import org.apache.cassandra.utils.concurrent.SimpleCondition; import org.apache.cassandra.utils.progress.ProgressEventType; @@ -60,7 +60,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -public class PreviewRepairTest extends DistributedTestBase +public class PreviewRepairTest extends TestBaseImpl { /** * makes sure that the repaired sstables are not matching on the two @@ -93,9 +93,9 @@ public class PreviewRepairTest extends DistributedTestBase cfs.enableAutoCompaction(); FBUtilities.waitOnFutures(CompactionManager.instance.submitBackground(cfs)); }); - Pair rs = cluster.get(1).callOnInstance(repair(options(true))); - assertTrue(rs.left); // preview repair should succeed - assertFalse(rs.right); // and we should see no mismatches + RepairResult rs = cluster.get(1).callOnInstance(repair(options(true))); + assertTrue(rs.success); // preview repair should succeed + assertFalse(rs.wasInconsistent); // and we should see no mismatches } } @@ -133,14 +133,14 @@ public class PreviewRepairTest extends DistributedTestBase // this pauses the validation request sent from node1 to node2 until we have run a full inc repair below cluster.filters().outbound().verbs(Verb.VALIDATION_REQ.id).from(1).to(2).messagesMatching(filter).drop(); - Future> rsFuture = es.submit(() -> cluster.get(1).callOnInstance(repair(options(true)))); + Future rsFuture = es.submit(() -> cluster.get(1).callOnInstance(repair(options(true)))); Thread.sleep(1000); // this needs to finish before the preview repair is unpaused on node2 cluster.get(1).callOnInstance(repair(options(false))); continuePreviewRepair.signalAll(); - Pair rs = rsFuture.get(); - assertFalse(rs.left); // preview repair should have failed - assertFalse(rs.right); // and no mismatches should have been reported + RepairResult rs = rsFuture.get(); + assertFalse(rs.success); // preview repair should have failed + assertFalse(rs.wasInconsistent); // and no mismatches should have been reported } finally { @@ -162,7 +162,7 @@ public class PreviewRepairTest extends DistributedTestBase insert(cluster.coordinator(1), 0, 100); cluster.forEach((node) -> node.flush(KEYSPACE)); - assertTrue(cluster.get(1).callOnInstance(repair(options(false))).left); + assertTrue(cluster.get(1).callOnInstance(repair(options(false))).success); insert(cluster.coordinator(1), 100, 100); cluster.forEach((node) -> node.flush(KEYSPACE)); @@ -181,15 +181,15 @@ public class PreviewRepairTest extends DistributedTestBase }); assertEquals(2, localRanges.size()); - Future> repairStatusFuture = es.submit(() -> cluster.get(1).callOnInstance(repair(options(true, localRanges.get(0))))); + Future repairStatusFuture = es.submit(() -> cluster.get(1).callOnInstance(repair(options(true, localRanges.get(0))))); Thread.sleep(1000); // wait for node1 to start validation compaction // this needs to finish before the preview repair is unpaused on node2 - assertTrue(cluster.get(1).callOnInstance(repair(options(false, localRanges.get(1)))).left); + assertTrue(cluster.get(1).callOnInstance(repair(options(false, localRanges.get(1)))).success); continuePreviewRepair.signalAll(); - Pair rs = repairStatusFuture.get(); - assertTrue(rs.left); // repair should succeed - assertFalse(rs.right); // and no mismatches + RepairResult rs = repairStatusFuture.get(); + assertTrue(rs.success); // repair should succeed + assertFalse(rs.wasInconsistent); // and no mismatches } finally { @@ -231,7 +231,7 @@ public class PreviewRepairTest extends DistributedTestBase /** * returns a pair with [repair success, was inconsistent] */ - private static IIsolatedExecutor.SerializableCallable> repair(Map options) + private static IIsolatedExecutor.SerializableCallable repair(Map options) { return () -> { SimpleCondition await = new SimpleCondition(); @@ -258,7 +258,7 @@ public class PreviewRepairTest extends DistributedTestBase { throw new RuntimeException(e); } - return Pair.create(success.get(), wasInconsistent.get()); + return new RepairResult(success.get(), wasInconsistent.get()); }; } diff --git a/test/distributed/org/apache/cassandra/distributed/test/QueryReplayerEndToEndTest.java b/test/distributed/org/apache/cassandra/distributed/test/QueryReplayerEndToEndTest.java index 9908fcc1c8..9202cb48d5 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/QueryReplayerEndToEndTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/QueryReplayerEndToEndTest.java @@ -31,13 +31,14 @@ import org.junit.Assert; import org.junit.Test; import org.apache.cassandra.cql3.QueryOptions; -import org.apache.cassandra.db.ConsistencyLevel; -import org.apache.cassandra.distributed.Cluster; +import org.apache.cassandra.distributed.api.ConsistencyLevel; import org.apache.cassandra.distributed.api.Feature; +import org.apache.cassandra.distributed.api.ICluster; +import org.apache.cassandra.distributed.api.IInvokableInstance; import org.apache.cassandra.fqltool.FQLQuery; import org.apache.cassandra.fqltool.QueryReplayer; -public class QueryReplayerEndToEndTest extends DistributedTestBase +public class QueryReplayerEndToEndTest extends TestBaseImpl { private final AtomicLong queryStartTimeGenerator = new AtomicLong(1000); private final AtomicInteger ckGenerator = new AtomicInteger(1); @@ -45,11 +46,13 @@ public class QueryReplayerEndToEndTest extends DistributedTestBase @Test public void testReplayAndCloseMultipleTimes() throws Throwable { - try (Cluster cluster = init(Cluster.create(3, conf -> conf.with(Feature.NATIVE_PROTOCOL, Feature.GOSSIP, Feature.NETWORK)))) + try (ICluster cluster = init(builder().withNodes(3) + .withConfig(conf -> conf.with(Feature.NATIVE_PROTOCOL, Feature.GOSSIP, Feature.NETWORK)) + .start())) { cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck))"); List hosts = cluster.stream() - .map(i -> i.config().broadcastAddressAndPort().address.getHostAddress()) + .map(i -> i.config().broadcastAddress().getAddress().getHostAddress()) .collect(Collectors.toList()); final int queriesCount = 3; diff --git a/test/distributed/org/apache/cassandra/distributed/test/ReadRepairTest.java b/test/distributed/org/apache/cassandra/distributed/test/ReadRepairTest.java index a8c5fa1a08..2a67476fb2 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/ReadRepairTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/ReadRepairTest.java @@ -18,29 +18,33 @@ package org.apache.cassandra.distributed.test; +import java.net.InetSocketAddress; import java.util.List; import org.junit.Test; -import org.apache.cassandra.db.ConsistencyLevel; import org.apache.cassandra.db.marshal.Int32Type; import org.apache.cassandra.dht.Murmur3Partitioner; import org.apache.cassandra.dht.Token; import org.apache.cassandra.distributed.Cluster; +import org.apache.cassandra.distributed.api.ConsistencyLevel; +import org.apache.cassandra.distributed.api.ICluster; +import org.apache.cassandra.distributed.shared.NetworkTopology; import org.apache.cassandra.locator.InetAddressAndPort; import org.apache.cassandra.service.PendingRangeCalculatorService; import org.apache.cassandra.service.StorageService; import static org.apache.cassandra.net.Verb.READ_REPAIR_REQ; import static org.apache.cassandra.net.Verb.READ_REQ; +import static org.apache.cassandra.distributed.shared.AssertUtils.*; -public class ReadRepairTest extends DistributedTestBase +public class ReadRepairTest extends TestBaseImpl { @Test public void readRepairTest() throws Throwable { - try (Cluster cluster = init(Cluster.create(3))) + try (ICluster cluster = init(builder().withNodes(3).start())) { cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck)) WITH read_repair='blocking'"); @@ -62,7 +66,7 @@ public class ReadRepairTest extends DistributedTestBase @Test public void failingReadRepairTest() throws Throwable { - try (Cluster cluster = init(Cluster.create(3))) + try (ICluster cluster = init(builder().withNodes(3).start())) { cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck)) WITH read_repair='blocking'"); @@ -71,7 +75,7 @@ public class ReadRepairTest extends DistributedTestBase assertRows(cluster.get(3).executeInternal("SELECT * FROM " + KEYSPACE + ".tbl WHERE pk = 1")); - cluster.verbs(READ_REPAIR_REQ).to(3).drop(); + cluster.filters().verbs(READ_REPAIR_REQ.id).to(3).drop(); assertRows(cluster.coordinator(1).execute("SELECT * FROM " + KEYSPACE + ".tbl WHERE pk = 1", ConsistencyLevel.QUORUM), row(1, 1, 1)); @@ -84,7 +88,7 @@ public class ReadRepairTest extends DistributedTestBase @Test public void movingTokenReadRepairTest() throws Throwable { - try (Cluster cluster = init(Cluster.create(4), 3)) + try (Cluster cluster = (Cluster) init(Cluster.create(4), 3)) { List tokens = cluster.tokens(); @@ -102,11 +106,11 @@ public class ReadRepairTest extends DistributedTestBase // write only to #4 cluster.get(4).executeInternal("INSERT INTO " + KEYSPACE + ".tbl (pk, ck, v) VALUES (?, 1, 1)", i); // mark #2 as leaving in #4 - cluster.get(4).acceptsOnInstance((InetAddressAndPort endpoint) -> { - StorageService.instance.getTokenMetadata().addLeavingEndpoint(endpoint); + cluster.get(4).acceptsOnInstance((InetSocketAddress endpoint) -> { + StorageService.instance.getTokenMetadata().addLeavingEndpoint(InetAddressAndPort.getByAddressOverrideDefaults(endpoint.getAddress(), endpoint.getPort())); PendingRangeCalculatorService.instance.update(); PendingRangeCalculatorService.instance.blockUntilFinished(); - }).accept(cluster.get(2).broadcastAddressAndPort()); + }).accept(cluster.get(2).broadcastAddress()); // prevent #4 from reading or writing to #3, so our QUORUM must contain #2 and #4 // since #1 is taking over the range, this means any read-repair must make it to #1 as well diff --git a/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorBase.java b/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorBase.java index 4651376498..fc058dbfe1 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorBase.java +++ b/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorBase.java @@ -33,7 +33,7 @@ import org.apache.cassandra.distributed.api.NodeToolResult; import org.apache.cassandra.distributed.test.DistributedRepairUtils.RepairParallelism; import org.apache.cassandra.distributed.test.DistributedRepairUtils.RepairType; -public class RepairCoordinatorBase extends DistributedTestBase +public class RepairCoordinatorBase extends TestBaseImpl { protected static Cluster CLUSTER; diff --git a/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorFailingMessageTest.java b/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorFailingMessageTest.java index ac31334c45..0d046497b9 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorFailingMessageTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorFailingMessageTest.java @@ -45,7 +45,7 @@ import static org.apache.cassandra.distributed.api.IMessageFilters.Matcher.of; @RunWith(Parameterized.class) @Ignore("Until CASSANDRA-15566 is in these tests all time out") -public class RepairCoordinatorFailingMessageTest extends DistributedTestBase implements Serializable +public class RepairCoordinatorFailingMessageTest extends TestBaseImpl implements Serializable { private static Cluster CLUSTER; diff --git a/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorFast.java b/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorFast.java index edcb9c3aab..b05706a3bf 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorFast.java +++ b/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorFast.java @@ -25,9 +25,9 @@ import org.junit.Assert; import org.junit.Assume; import org.junit.Test; -import org.apache.cassandra.db.ConsistencyLevel; import org.apache.cassandra.dht.Range; import org.apache.cassandra.dht.Token; +import org.apache.cassandra.distributed.api.ConsistencyLevel; import org.apache.cassandra.distributed.api.IMessageFilters; import org.apache.cassandra.distributed.api.LongTokenRange; import org.apache.cassandra.distributed.api.NodeToolResult; diff --git a/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorSlow.java b/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorSlow.java index 32538ec61a..7be8ed15ef 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorSlow.java +++ b/test/distributed/org/apache/cassandra/distributed/test/RepairCoordinatorSlow.java @@ -31,7 +31,6 @@ import org.junit.Test; import org.apache.cassandra.distributed.api.IMessageFilters; import org.apache.cassandra.distributed.api.NodeToolResult; -import org.apache.cassandra.distributed.impl.MessageFilters; import org.apache.cassandra.distributed.test.DistributedRepairUtils.RepairParallelism; import org.apache.cassandra.distributed.test.DistributedRepairUtils.RepairType; import org.apache.cassandra.gms.FailureDetector; diff --git a/test/distributed/org/apache/cassandra/distributed/test/RepairDigestTrackingTest.java b/test/distributed/org/apache/cassandra/distributed/test/RepairDigestTrackingTest.java index 1af329f455..4e44543366 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/RepairDigestTrackingTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/RepairDigestTrackingTest.java @@ -22,15 +22,14 @@ import java.io.IOException; import java.io.Serializable; import java.util.EnumSet; import java.util.Map; -import java.util.Set; import java.util.concurrent.TimeUnit; import org.junit.Assert; import org.junit.Test; -import org.apache.cassandra.db.ConsistencyLevel; import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.distributed.Cluster; +import org.apache.cassandra.distributed.api.ConsistencyLevel; import org.apache.cassandra.io.sstable.Descriptor; import org.apache.cassandra.io.sstable.format.SSTableReader; import org.apache.cassandra.io.sstable.metadata.MetadataComponent; @@ -39,13 +38,13 @@ import org.apache.cassandra.io.sstable.metadata.StatsMetadata; import org.apache.cassandra.service.ActiveRepairService; import org.apache.cassandra.service.StorageProxy; -public class RepairDigestTrackingTest extends DistributedTestBase implements Serializable +public class RepairDigestTrackingTest extends TestBaseImpl implements Serializable// TODO: why serializable? { @Test public void testInconsistenciesFound() throws Throwable { - try (Cluster cluster = init(Cluster.create(2))) + try (Cluster cluster = (Cluster) init(builder().withNodes(2).start())) { cluster.get(1).runOnInstance(() -> { @@ -117,7 +116,7 @@ public class RepairDigestTrackingTest extends DistributedTestBase implements Ser @Test public void testPurgeableTombstonesAreIgnored() throws Throwable { - try (Cluster cluster = init(Cluster.create(2))) + try (Cluster cluster = (Cluster) init(builder().withNodes(2).start())) { cluster.get(1).runOnInstance(() -> { diff --git a/test/distributed/org/apache/cassandra/distributed/test/RepairTest.java b/test/distributed/org/apache/cassandra/distributed/test/RepairTest.java index 0460dec781..f37a3d8ff6 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/RepairTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/RepairTest.java @@ -30,30 +30,34 @@ import org.junit.BeforeClass; import org.junit.Test; import org.apache.cassandra.distributed.Cluster; -import org.apache.cassandra.distributed.impl.InstanceConfig; +import org.apache.cassandra.distributed.api.ICluster; +import org.apache.cassandra.distributed.api.IInstanceConfig; +import org.apache.cassandra.distributed.api.IInvokableInstance; import org.apache.cassandra.service.StorageService; import org.apache.cassandra.utils.concurrent.SimpleCondition; import org.apache.cassandra.utils.progress.ProgressEventType; import static java.util.concurrent.TimeUnit.MINUTES; -import static org.apache.cassandra.distributed.impl.ExecUtil.rethrow; +import static org.apache.cassandra.distributed.test.ExecUtil.rethrow; import static org.apache.cassandra.distributed.api.Feature.GOSSIP; import static org.apache.cassandra.distributed.api.Feature.NETWORK; +import static org.apache.cassandra.distributed.shared.AssertUtils.*; -public class RepairTest extends DistributedTestBase +public class RepairTest extends TestBaseImpl { private static final String insert = withKeyspace("INSERT INTO %s.test (k, c1, c2) VALUES (?, 'value1', 'value2');"); private static final String query = withKeyspace("SELECT k, c1, c2 FROM %s.test WHERE k = ?;"); - private static Cluster cluster; - private static void insert(Cluster cluster, int start, int end, int ... nodes) + private static ICluster cluster; + + private static void insert(ICluster cluster, int start, int end, int ... nodes) { for (int i = start ; i < end ; ++i) for (int node : nodes) cluster.get(node).executeInternal(insert, Integer.toString(i)); } - private static void verify(Cluster cluster, int start, int end, int ... nodes) + private static void verify(ICluster cluster, int start, int end, int ... nodes) { for (int i = start ; i < end ; ++i) { @@ -68,13 +72,13 @@ public class RepairTest extends DistributedTestBase } } - private static void flush(Cluster cluster, int ... nodes) + private static void flush(ICluster cluster, int ... nodes) { for (int node : nodes) cluster.get(node).runOnInstance(rethrow(() -> StorageService.instance.forceKeyspaceFlush(KEYSPACE))); } - private static Cluster create(Consumer configModifier) throws IOException + private static ICluster create(Consumer configModifier) throws IOException { configModifier = configModifier.andThen( config -> config.set("hinted_handoff_enabled", false) @@ -83,10 +87,10 @@ public class RepairTest extends DistributedTestBase .with(GOSSIP) ); - return init(Cluster.build(3).withConfig(configModifier).start()); + return init(Cluster.build().withNodes(3).withConfig(configModifier).start()); } - private void repair(Cluster cluster, Map options) + private void repair(ICluster cluster, Map options) { cluster.get(1).runOnInstance(rethrow(() -> { SimpleCondition await = new SimpleCondition(); @@ -98,7 +102,7 @@ public class RepairTest extends DistributedTestBase })); } - void populate(Cluster cluster, String compression) + void populate(ICluster cluster, String compression) throws Exception { try { @@ -123,7 +127,7 @@ public class RepairTest extends DistributedTestBase } - void repair(Cluster cluster, boolean sequential, String compression) + void repair(ICluster cluster, boolean sequential, String compression) throws Exception { populate(cluster, compression); repair(cluster, ImmutableMap.of("parallelism", sequential ? "sequential" : "parallel")); @@ -137,44 +141,44 @@ public class RepairTest extends DistributedTestBase } @AfterClass - public static void closeCluster() + public static void closeCluster() throws Exception { if (cluster != null) cluster.close(); } @Test - public void testSequentialRepairWithDefaultCompression() + public void testSequentialRepairWithDefaultCompression() throws Exception { repair(cluster, true, "{'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}"); } @Test - public void testParallelRepairWithDefaultCompression() + public void testParallelRepairWithDefaultCompression() throws Exception { repair(cluster, false, "{'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}"); } @Test - public void testSequentialRepairWithMinCompressRatio() + public void testSequentialRepairWithMinCompressRatio() throws Exception { repair(cluster, true, "{'class': 'org.apache.cassandra.io.compress.LZ4Compressor', 'min_compress_ratio': 4.0}"); } @Test - public void testParallelRepairWithMinCompressRatio() + public void testParallelRepairWithMinCompressRatio() throws Exception { repair(cluster, false, "{'class': 'org.apache.cassandra.io.compress.LZ4Compressor', 'min_compress_ratio': 4.0}"); } @Test - public void testSequentialRepairWithoutCompression() + public void testSequentialRepairWithoutCompression() throws Exception { repair(cluster, true, "{'enabled': false}"); } @Test - public void testParallelRepairWithoutCompression() + public void testParallelRepairWithoutCompression() throws Exception { repair(cluster, false, "{'enabled': false}"); } diff --git a/test/distributed/org/apache/cassandra/distributed/test/ResourceLeakTest.java b/test/distributed/org/apache/cassandra/distributed/test/ResourceLeakTest.java index fb5f758ccb..5430800c02 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/ResourceLeakTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/ResourceLeakTest.java @@ -26,7 +26,6 @@ import java.nio.file.Path; import java.sql.Date; import java.text.SimpleDateFormat; import java.time.Instant; -import java.util.List; import java.util.function.Consumer; import javax.management.MBeanServer; @@ -34,18 +33,14 @@ import org.junit.Ignore; import org.junit.Test; import com.sun.management.HotSpotDiagnosticMXBean; -import org.apache.cassandra.db.ConsistencyLevel; -import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.distributed.Cluster; -import org.apache.cassandra.distributed.impl.InstanceConfig; -import org.apache.cassandra.gms.Gossiper; -import org.apache.cassandra.service.CassandraDaemon; -import org.apache.cassandra.utils.FBUtilities; +import org.apache.cassandra.distributed.api.ConsistencyLevel; +import org.apache.cassandra.distributed.api.IInstanceConfig; import org.apache.cassandra.utils.SigarLibrary; import static org.apache.cassandra.distributed.api.Feature.GOSSIP; -import static org.apache.cassandra.distributed.api.Feature.NETWORK; import static org.apache.cassandra.distributed.api.Feature.NATIVE_PROTOCOL; +import static org.apache.cassandra.distributed.api.Feature.NETWORK; /* Resource Leak Test - useful when tracking down issues with in-JVM framework cleanup. * All objects referencing the InstanceClassLoader need to be garbage collected or @@ -60,7 +55,7 @@ import static org.apache.cassandra.distributed.api.Feature.NATIVE_PROTOCOL; * but it shows that the file handles for Data/Index files are being leaked. */ @Ignore -public class ResourceLeakTest extends DistributedTestBase +public class ResourceLeakTest extends TestBaseImpl { // Parameters to adjust while hunting for leaks final int numTestLoops = 1; // Set this value high to crash on leaks, or low when tracking down an issue. @@ -142,21 +137,18 @@ public class ResourceLeakTest extends DistributedTestBase } } - void doTest(int numClusterNodes, Consumer updater) throws Throwable + void doTest(int numClusterNodes, Consumer updater) throws Throwable { for (int loop = 0; loop < numTestLoops; loop++) { System.out.println(String.format("========== Starting loop %03d ========", loop)); - try (Cluster cluster = Cluster.build(numClusterNodes).withConfig(updater).start()) + try (Cluster cluster = (Cluster) builder().withNodes(numClusterNodes).withConfig(updater).start()) { - if (cluster.get(1).config().has(GOSSIP)) // Wait for gossip to settle on the seed node - cluster.get(1).runOnInstance(() -> Gossiper.waitToSettle()); - init(cluster); String tableName = "tbl" + loop; cluster.schemaChange("CREATE TABLE " + KEYSPACE + "." + tableName + " (pk int, ck int, v int, PRIMARY KEY (pk, ck))"); cluster.coordinator(1).execute("INSERT INTO " + KEYSPACE + "." + tableName + "(pk,ck,v) VALUES (0,0,0)", ConsistencyLevel.ALL); - cluster.get(1).callOnInstance(() -> FBUtilities.waitOnFutures(Keyspace.open(KEYSPACE).flush())); + cluster.get(1).flush(KEYSPACE); if (dumpEveryLoop) { dumpResources(String.format("loop%03d", loop)); diff --git a/test/distributed/org/apache/cassandra/distributed/test/SimpleReadWriteTest.java b/test/distributed/org/apache/cassandra/distributed/test/SimpleReadWriteTest.java index e5ee240d83..f635a28bcf 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/SimpleReadWriteTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/SimpleReadWriteTest.java @@ -19,36 +19,30 @@ package org.apache.cassandra.distributed.test; import org.junit.Assert; -import org.junit.BeforeClass; import org.junit.Test; import org.apache.cassandra.config.DatabaseDescriptor; -import org.apache.cassandra.db.ConsistencyLevel; import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.distributed.Cluster; -import org.apache.cassandra.distributed.impl.IInvokableInstance; +import org.apache.cassandra.distributed.api.ConsistencyLevel; +import org.apache.cassandra.distributed.api.ICluster; +import org.apache.cassandra.distributed.api.IInvokableInstance; import org.apache.cassandra.metrics.ReadRepairMetrics; import static org.apache.cassandra.distributed.api.Feature.NETWORK; -import static org.apache.cassandra.net.Verb.READ_REPAIR_RSP; -import static org.junit.Assert.assertEquals; - -import static org.apache.cassandra.net.Verb.READ_REPAIR_REQ; +import static org.apache.cassandra.distributed.shared.AssertUtils.*; import static org.apache.cassandra.net.OutboundConnections.LARGE_MESSAGE_THRESHOLD; +import static org.apache.cassandra.net.Verb.READ_REPAIR_REQ; +import static org.apache.cassandra.net.Verb.READ_REPAIR_RSP; import static org.junit.Assert.fail; -public class SimpleReadWriteTest extends DistributedTestBase +// TODO: this test should be removed after running in-jvm dtests is set up via the shared API repository +public class SimpleReadWriteTest extends TestBaseImpl { - @BeforeClass - public static void before() - { - DatabaseDescriptor.clientInitialization(); - } - @Test public void coordinatorReadTest() throws Throwable { - try (Cluster cluster = init(Cluster.create(3))) + try (ICluster cluster = init(builder().withNodes(3).start())) { cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck)) WITH read_repair='none'"); @@ -68,7 +62,7 @@ public class SimpleReadWriteTest extends DistributedTestBase @Test public void largeMessageTest() throws Throwable { - try (Cluster cluster = init(Cluster.create(2))) + try (ICluster cluster = init(builder().withNodes(2).start())) { cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v text, PRIMARY KEY (pk, ck))"); StringBuilder builder = new StringBuilder(); @@ -88,7 +82,7 @@ public class SimpleReadWriteTest extends DistributedTestBase @Test public void coordinatorWriteTest() throws Throwable { - try (Cluster cluster = init(Cluster.create(3))) + try (ICluster cluster = init(builder().withNodes(3).start())) { cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck)) WITH read_repair='none'"); @@ -110,7 +104,7 @@ public class SimpleReadWriteTest extends DistributedTestBase @Test public void readRepairTest() throws Throwable { - try (Cluster cluster = init(Cluster.create(3))) + try (ICluster cluster = init(builder().withNodes(3).start())) { cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck)) WITH read_repair='blocking'"); @@ -133,7 +127,7 @@ public class SimpleReadWriteTest extends DistributedTestBase public void readRepairTimeoutTest() throws Throwable { final long reducedReadTimeout = 3000L; - try (Cluster cluster = init(Cluster.create(3))) + try (Cluster cluster = (Cluster) init(builder().withNodes(3).start())) { cluster.forEach(i -> i.runOnInstance(() -> DatabaseDescriptor.setReadRpcTimeout(reducedReadTimeout))); cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck)) WITH read_repair='blocking'"); @@ -218,7 +212,7 @@ public class SimpleReadWriteTest extends DistributedTestBase @Test public void writeWithSchemaDisagreement() throws Throwable { - try (Cluster cluster = init(Cluster.build(3).withConfig(config -> config.with(NETWORK)).start())) + try (ICluster cluster = init(builder().withNodes(3).withConfig(config -> config.with(NETWORK)).start())) { cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v1 int, PRIMARY KEY (pk, ck))"); @@ -253,7 +247,7 @@ public class SimpleReadWriteTest extends DistributedTestBase @Test public void readWithSchemaDisagreement() throws Throwable { - try (Cluster cluster = init(Cluster.create(3, config -> config.with(NETWORK)))) + try (ICluster cluster = init(builder().withNodes(3).withConfig(config -> config.with(NETWORK)).start())) { cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v1 int, PRIMARY KEY (pk, ck))"); @@ -287,7 +281,7 @@ public class SimpleReadWriteTest extends DistributedTestBase @Test public void simplePagedReadsTest() throws Throwable { - try (Cluster cluster = init(Cluster.create(3))) + try (ICluster cluster = init(builder().withNodes(3).start())) { cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck))"); @@ -315,7 +309,7 @@ public class SimpleReadWriteTest extends DistributedTestBase @Test public void pagingWithRepairTest() throws Throwable { - try (Cluster cluster = init(Cluster.create(3))) + try (ICluster cluster = init(builder().withNodes(3).start())) { cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck))"); @@ -347,8 +341,8 @@ public class SimpleReadWriteTest extends DistributedTestBase @Test public void pagingTests() throws Throwable { - try (Cluster cluster = init(Cluster.create(3)); - Cluster singleNode = init(Cluster.build(1).withSubnet(1).start())) + try (ICluster cluster = init(builder().withNodes(3).start()); + ICluster singleNode = init(builder().withNodes(1).withSubnet(1).start())) { cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck))"); singleNode.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck))"); @@ -402,7 +396,7 @@ public class SimpleReadWriteTest extends DistributedTestBase @Test public void metricsCountQueriesTest() throws Throwable { - try (Cluster cluster = init(Cluster.create(2))) + try (ICluster cluster = init(Cluster.create(2))) { cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck))"); for (int i = 0; i < 100; i++) @@ -415,8 +409,8 @@ public class SimpleReadWriteTest extends DistributedTestBase readCount1 = readCount(cluster.get(1)) - readCount1; readCount2 = readCount(cluster.get(2)) - readCount2; - assertEquals(readCount1, readCount2); - assertEquals(100, readCount1); + Assert.assertEquals(readCount1, readCount2); + Assert.assertEquals(100, readCount1); } } diff --git a/test/distributed/org/apache/cassandra/distributed/test/StreamingTest.java b/test/distributed/org/apache/cassandra/distributed/test/StreamingTest.java index 22cd5907c7..bafd03d4f3 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/StreamingTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/StreamingTest.java @@ -29,12 +29,12 @@ import org.apache.cassandra.service.StorageService; import static org.apache.cassandra.distributed.api.Feature.NETWORK; -public class StreamingTest extends DistributedTestBase +public class StreamingTest extends TestBaseImpl { private void testStreaming(int nodes, int replicationFactor, int rowCount, String compactionStrategy) throws Throwable { - try (Cluster cluster = Cluster.create(nodes, config -> config.with(NETWORK))) + try (Cluster cluster = (Cluster) builder().withNodes(nodes).withConfig(config -> config.with(NETWORK)).start()) { cluster.schemaChange("CREATE KEYSPACE " + KEYSPACE + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': " + replicationFactor + "};"); cluster.schemaChange(String.format("CREATE TABLE %s.cf (k text, c1 text, c2 text, PRIMARY KEY (k)) WITH compaction = {'class': '%s', 'enabled': 'true'}", KEYSPACE, compactionStrategy)); diff --git a/test/distributed/org/apache/cassandra/distributed/test/TestBaseImpl.java b/test/distributed/org/apache/cassandra/distributed/test/TestBaseImpl.java new file mode 100644 index 0000000000..97524309e8 --- /dev/null +++ b/test/distributed/org/apache/cassandra/distributed/test/TestBaseImpl.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.distributed.test; + +import org.junit.After; +import org.junit.BeforeClass; + +import org.apache.cassandra.distributed.Cluster; +import org.apache.cassandra.distributed.api.ICluster; +import org.apache.cassandra.distributed.api.IInstance; +import org.apache.cassandra.distributed.shared.Builder; +import org.apache.cassandra.distributed.shared.DistributedTestBase; + +public class TestBaseImpl extends DistributedTestBase +{ + @After + public void afterEach() { + super.afterEach(); + } + + @BeforeClass + public static void beforeClass() throws Throwable { + ICluster.setup(); + } + + @Override + public Builder builder() { + // This is definitely not the smartest solution, but given the complexity of the alternatives and low risk, we can just rely on the + // fact that this code is going to work accross _all_ versions. + return (Builder) Cluster.build(); + } +} diff --git a/test/distributed/org/apache/cassandra/distributed/upgrade/MixedModeReadRepairTest.java b/test/distributed/org/apache/cassandra/distributed/upgrade/MixedModeReadRepairTest.java index 31f4b84ccf..6df72b8bb8 100644 --- a/test/distributed/org/apache/cassandra/distributed/upgrade/MixedModeReadRepairTest.java +++ b/test/distributed/org/apache/cassandra/distributed/upgrade/MixedModeReadRepairTest.java @@ -20,11 +20,10 @@ package org.apache.cassandra.distributed.upgrade; import org.junit.Test; -import org.apache.cassandra.db.ConsistencyLevel; -import org.apache.cassandra.distributed.impl.Versions; -import org.apache.cassandra.distributed.test.DistributedTestBase; +import org.apache.cassandra.distributed.api.ConsistencyLevel; +import org.apache.cassandra.distributed.shared.Versions; -import static org.apache.cassandra.distributed.impl.Versions.find; +import static org.apache.cassandra.distributed.shared.Versions.find; public class MixedModeReadRepairTest extends UpgradeTestBase { @@ -35,17 +34,17 @@ public class MixedModeReadRepairTest extends UpgradeTestBase .nodes(2) .upgrade(Versions.Major.v22, Versions.Major.v30) .nodesToUpgrade(2) - .setup((cluster) -> cluster.schemaChange("CREATE TABLE " + DistributedTestBase.KEYSPACE + ".tbl (pk ascii, b boolean, v blob, PRIMARY KEY (pk)) WITH COMPACT STORAGE")) + .setup((cluster) -> cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk ascii, b boolean, v blob, PRIMARY KEY (pk)) WITH COMPACT STORAGE")) .runAfterClusterUpgrade((cluster) -> { // now node2 is 3.0 and node1 is 2.2 // make sure 2.2 side does not get the mutation - cluster.get(2).executeInternal("DELETE FROM " + DistributedTestBase.KEYSPACE + ".tbl WHERE pk = ?", - "something"); + cluster.get(2).executeInternal("DELETE FROM " + KEYSPACE + ".tbl WHERE pk = ?", + "something"); // trigger a read repair - cluster.coordinator(1).execute("SELECT * FROM " + DistributedTestBase.KEYSPACE + ".tbl WHERE pk = ?", + cluster.coordinator(1).execute("SELECT * FROM " + KEYSPACE + ".tbl WHERE pk = ?", ConsistencyLevel.ALL, "something"); - cluster.get(1).flush(DistributedTestBase.KEYSPACE); + cluster.get(1).flush(KEYSPACE); // upgrade node1 to 3.0 cluster.get(1).shutdown().get(); Versions allVersions = find(); @@ -53,7 +52,7 @@ public class MixedModeReadRepairTest extends UpgradeTestBase cluster.get(1).startup(); // and make sure the sstables are readable - cluster.get(1).forceCompact(DistributedTestBase.KEYSPACE, "tbl"); + cluster.get(1).forceCompact(KEYSPACE, "tbl"); }).run(); } -} +} \ No newline at end of file diff --git a/test/distributed/org/apache/cassandra/distributed/upgrade/UpgradeTest.java b/test/distributed/org/apache/cassandra/distributed/upgrade/UpgradeTest.java index 2e63725baf..88dd0f9433 100644 --- a/test/distributed/org/apache/cassandra/distributed/upgrade/UpgradeTest.java +++ b/test/distributed/org/apache/cassandra/distributed/upgrade/UpgradeTest.java @@ -20,9 +20,9 @@ package org.apache.cassandra.distributed.upgrade; import org.junit.Test; -import org.apache.cassandra.db.ConsistencyLevel; -import org.apache.cassandra.distributed.impl.Versions; -import org.apache.cassandra.distributed.test.DistributedTestBase; +import org.apache.cassandra.distributed.api.ConsistencyLevel; +import org.apache.cassandra.distributed.shared.Versions; +import static org.apache.cassandra.distributed.shared.AssertUtils.*; public class UpgradeTest extends UpgradeTestBase { @@ -31,23 +31,22 @@ public class UpgradeTest extends UpgradeTestBase public void upgradeTest() throws Throwable { new TestCase() - .upgrade(Versions.Major.v22, Versions.Major.v30, Versions.Major.v3X) - .upgrade(Versions.Major.v30, Versions.Major.v3X, Versions.Major.v4) - .setup((cluster) -> { - cluster.schemaChange("CREATE TABLE " + DistributedTestBase.KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck))"); + .upgrade(Versions.Major.v22, Versions.Major.v30, Versions.Major.v3X) + .upgrade(Versions.Major.v30, Versions.Major.v3X, Versions.Major.v4) + .setup((cluster) -> { + cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, ck int, v int, PRIMARY KEY (pk, ck))"); - cluster.get(1).executeInternal("INSERT INTO " + DistributedTestBase.KEYSPACE + ".tbl (pk, ck, v) VALUES (1, 1, 1)"); - cluster.get(2).executeInternal("INSERT INTO " + DistributedTestBase.KEYSPACE + ".tbl (pk, ck, v) VALUES (1, 2, 2)"); - cluster.get(3).executeInternal("INSERT INTO " + DistributedTestBase.KEYSPACE + ".tbl (pk, ck, v) VALUES (1, 3, 3)"); - }) - .runAfterClusterUpgrade((cluster) -> { - DistributedTestBase.assertRows(cluster.coordinator(1).execute("SELECT * FROM " + DistributedTestBase.KEYSPACE + ".tbl WHERE pk = ?", - ConsistencyLevel.ALL, - 1), - DistributedTestBase.row(1, 1, 1), - DistributedTestBase.row(1, 2, 2), - DistributedTestBase.row(1, 3, 3)); - }).run(); + cluster.get(1).executeInternal("INSERT INTO " + KEYSPACE + ".tbl (pk, ck, v) VALUES (1, 1, 1)"); + cluster.get(2).executeInternal("INSERT INTO " + KEYSPACE + ".tbl (pk, ck, v) VALUES (1, 2, 2)"); + cluster.get(3).executeInternal("INSERT INTO " + KEYSPACE + ".tbl (pk, ck, v) VALUES (1, 3, 3)"); + }) + .runAfterClusterUpgrade((cluster) -> { + assertRows(cluster.coordinator(1).execute("SELECT * FROM " + KEYSPACE + ".tbl WHERE pk = ?", + ConsistencyLevel.ALL, + 1), + row(1, 1, 1), + row(1, 2, 2), + row(1, 3, 3)); + }).run(); } - -} +} \ No newline at end of file diff --git a/test/distributed/org/apache/cassandra/distributed/upgrade/UpgradeTestBase.java b/test/distributed/org/apache/cassandra/distributed/upgrade/UpgradeTestBase.java index bf28843596..afe6db890a 100644 --- a/test/distributed/org/apache/cassandra/distributed/upgrade/UpgradeTestBase.java +++ b/test/distributed/org/apache/cassandra/distributed/upgrade/UpgradeTestBase.java @@ -24,18 +24,25 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import org.apache.cassandra.db.MutableDeletionInfo; import org.apache.cassandra.distributed.UpgradeableCluster; +import org.apache.cassandra.distributed.api.ICluster; +import org.apache.cassandra.distributed.api.IInstance; import org.apache.cassandra.distributed.impl.Instance; -import org.apache.cassandra.distributed.impl.Versions; -import org.apache.cassandra.distributed.impl.Versions.Version; -import org.apache.cassandra.distributed.test.DistributedTestBase; -import static org.apache.cassandra.distributed.impl.Versions.Major; -import static org.apache.cassandra.distributed.impl.Versions.find; +import org.apache.cassandra.distributed.shared.Builder; +import org.apache.cassandra.distributed.shared.DistributedTestBase; +import org.apache.cassandra.distributed.shared.Versions; +import static org.apache.cassandra.distributed.shared.Versions.Version; +import static org.apache.cassandra.distributed.shared.Versions.Major; +import static org.apache.cassandra.distributed.shared.Versions.find; public class UpgradeTestBase extends DistributedTestBase { + public Builder builder() + { + return (Builder) UpgradeableCluster.build(); + } + public static interface RunOnCluster { public void run(UpgradeableCluster cluster) throws Throwable; diff --git a/test/unit/org/apache/cassandra/CassandraIsolatedJunit4ClassRunner.java b/test/unit/org/apache/cassandra/CassandraIsolatedJunit4ClassRunner.java index 5af6b1aa9f..90e38967f2 100644 --- a/test/unit/org/apache/cassandra/CassandraIsolatedJunit4ClassRunner.java +++ b/test/unit/org/apache/cassandra/CassandraIsolatedJunit4ClassRunner.java @@ -25,7 +25,9 @@ import java.util.function.Predicate; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.InitializationError; -import org.apache.cassandra.distributed.impl.Versions; +import org.apache.cassandra.distributed.impl.AbstractCluster; +import org.apache.cassandra.distributed.shared.Versions; +import org.apache.cassandra.utils.FBUtilities; /** * @@ -66,7 +68,7 @@ public class CassandraIsolatedJunit4ClassRunner extends BlockJUnit4ClassRunner { public CassandraIsolatedClassLoader() { - super(Versions.CURRENT.classpath); + super(AbstractCluster.CURRENT_VERSION.classpath); } @Override diff --git a/test/unit/org/apache/cassandra/LogbackStatusListener.java b/test/unit/org/apache/cassandra/LogbackStatusListener.java index d16058bf61..1f95bd4936 100644 --- a/test/unit/org/apache/cassandra/LogbackStatusListener.java +++ b/test/unit/org/apache/cassandra/LogbackStatusListener.java @@ -33,7 +33,7 @@ import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.spi.LoggerContextListener; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.StatusListener; -import org.apache.cassandra.distributed.impl.InstanceClassLoader; +import org.apache.cassandra.distributed.shared.InstanceClassLoader; /* * Listen for logback readiness and then redirect stdout/stderr to logback diff --git a/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java b/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java index 534bea9e8a..e7870823e7 100644 --- a/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java +++ b/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java @@ -97,9 +97,9 @@ public class DatabaseDescriptorRefTest "org.apache.cassandra.dht.IPartitioner", "org.apache.cassandra.distributed.api.IInstance", "org.apache.cassandra.distributed.api.IIsolatedExecutor", - "org.apache.cassandra.distributed.impl.InstanceClassLoader", + "org.apache.cassandra.distributed.shared.InstanceClassLoader", "org.apache.cassandra.distributed.impl.InstanceConfig", - "org.apache.cassandra.distributed.impl.IInvokableInstance", + "org.apache.cassandra.distributed.api.IInvokableInstance", "org.apache.cassandra.distributed.impl.InvokableInstance$CallableNoExcept", "org.apache.cassandra.distributed.impl.InvokableInstance$InstanceFunction", "org.apache.cassandra.distributed.impl.InvokableInstance$SerializableBiConsumer",