Merge branch 'cassandra-3.11' into trunk

This commit is contained in:
Alex Petrov 2020-03-27 19:13:17 +01:00
commit 0934730c2b
59 changed files with 647 additions and 2167 deletions

View File

@ -551,6 +551,7 @@
<dependency groupId="org.mockito" artifactId="mockito-core" version="3.2.4" />
<dependency groupId="org.quicktheories" artifactId="quicktheories" version="0.25" />
<dependency groupId="com.google.code.java-allocation-instrumenter" artifactId="java-allocation-instrumenter" version="${allocation-instrumenter.version}" />
<dependency groupId="org.apache.cassandra" artifactId="dtest-api" version="0.0.1" />
<dependency groupId="org.apache.rat" artifactId="apache-rat" version="0.10">
<exclusion groupId="commons-lang" artifactId="commons-lang"/>
</dependency>
@ -686,6 +687,7 @@
<dependency groupId="org.mockito" artifactId="mockito-core" />
<dependency groupId="org.quicktheories" artifactId="quicktheories" />
<dependency groupId="com.google.code.java-allocation-instrumenter" artifactId="java-allocation-instrumenter" version="${allocation-instrumenter.version}" />
<dependency groupId="org.apache.cassandra" artifactId="dtest-api" />
<dependency groupId="org.psjava" artifactId="psjava" version="0.1.19" />
<dependency groupId="org.apache.rat" artifactId="apache-rat"/>
<dependency groupId="org.apache.hadoop" artifactId="hadoop-core"/>

View File

@ -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<IInvokableInstance> implements ICluster, AutoCloseable
public class Cluster extends AbstractCluster<IInvokableInstance>
{
private Cluster(File root, Versions.Version version, List<InstanceConfig> configs, ClassLoader sharedClassLoader)
private Cluster(File root, Versions.Version version, List<IInstanceConfig> 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<IInvokableInstance, Cluster> build()
{
return new Builder<>(Cluster::new);
return new Builder<IInvokableInstance, Cluster>(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<IInvokableInstance, Cluster> build(int nodeCount)
@ -55,7 +69,7 @@ public class Cluster extends AbstractCluster<IInvokableInstance> implements IClu
return build().withNodes(nodeCount);
}
public static Cluster create(int nodeCount, Consumer<InstanceConfig> configUpdater) throws IOException
public static Cluster create(int nodeCount, Consumer<IInstanceConfig> configUpdater) throws IOException
{
return build(nodeCount).withConfig(configUpdater).start();
}

View File

@ -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<IUpgradeableInstance> implements ICluster, AutoCloseable
public class UpgradeableCluster extends AbstractCluster<IUpgradeableInstance> implements AutoCloseable
{
private UpgradeableCluster(File root, Versions.Version version, List<InstanceConfig> configs, ClassLoader sharedClassLoader)
private UpgradeableCluster(File root, Versions.Version version, List<IInstanceConfig> 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<IUpgradeableInstance, UpgradeableCluster> build()
{
return new Builder<>(UpgradeableCluster::new);
return new Builder<IUpgradeableInstance, UpgradeableCluster>(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<IUpgradeableInstance, UpgradeableCluster> build(int nodeCount)

View File

@ -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
}

View File

@ -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<? extends IInstance> stream();
Stream<? extends IInstance> stream(String dcName);
Stream<? extends IInstance> stream(String dcName, String rackName);
IMessageFilters filters();
}

View File

@ -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<Object[]> executeWithPaging(String query, Enum<?> consistencyLevel, int pageSize, Object... boundValues);
Future<Object[][]> asyncExecuteWithTracing(UUID sessionId, String query, Enum<?> consistencyLevel, Object... boundValues);
Object[][] executeWithTracing(UUID sessionId, String query, Enum<?> consistencyLevel, Object... boundValues);
}

View File

@ -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<Void> shutdown();
Future<Void> 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);
}

View File

@ -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);
}

View File

@ -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<O> extends Callable<O> { public O call(); }
public interface SerializableCallable<O> extends CallableNoExcept<O>, Serializable { }
public interface SerializableRunnable extends Runnable, Serializable {}
public interface SerializableConsumer<O> extends Consumer<O>, Serializable {}
public interface SerializableBiConsumer<I1, I2> extends BiConsumer<I1, I2>, Serializable {}
public interface SerializableFunction<I, O> extends Function<I, O>, Serializable {}
public interface SerializableBiFunction<I1, I2, O> extends BiFunction<I1, I2, O>, Serializable {}
public interface TriFunction<I1, I2, I3, O>
{
O apply(I1 i1, I2 i2, I3 i3);
}
public interface SerializableTriFunction<I1, I2, I3, O> extends Serializable, TriFunction<I1, I2, I3, O> { }
Future<Void> shutdown();
/**
* Convert the execution to one performed asynchronously on the IsolatedExecutor, returning a Future of the execution result
*/
<O> CallableNoExcept<Future<O>> async(CallableNoExcept<O> call);
/**
* Convert the execution to one performed synchronously on the IsolatedExecutor
*/
<O> CallableNoExcept<O> sync(CallableNoExcept<O> call);
/**
* Convert the execution to one performed asynchronously on the IsolatedExecutor, returning a Future of the execution result
*/
CallableNoExcept<Future<?>> 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
*/
<I> Function<I, Future<?>> async(Consumer<I> consumer);
/**
* Convert the execution to one performed synchronously on the IsolatedExecutor
*/
<I> Consumer<I> sync(Consumer<I> consumer);
/**
* Convert the execution to one performed asynchronously on the IsolatedExecutor, returning a Future of the execution result
*/
<I1, I2> BiFunction<I1, I2, Future<?>> async(BiConsumer<I1, I2> consumer);
/**
* Convert the execution to one performed synchronously on the IsolatedExecutor
*/
<I1, I2> BiConsumer<I1, I2> sync(BiConsumer<I1, I2> consumer);
/**
* Convert the execution to one performed asynchronously on the IsolatedExecutor, returning a Future of the execution result
*/
<I, O> Function<I, Future<O>> async(Function<I, O> f);
/**
* Convert the execution to one performed synchronously on the IsolatedExecutor
*/
<I, O> Function<I, O> sync(Function<I, O> f);
/**
* Convert the execution to one performed asynchronously on the IsolatedExecutor, returning a Future of the execution result
*/
<I1, I2, O> BiFunction<I1, I2, Future<O>> async(BiFunction<I1, I2, O> f);
/**
* Convert the execution to one performed synchronously on the IsolatedExecutor
*/
<I1, I2, O> BiFunction<I1, I2, O> sync(BiFunction<I1, I2, O> f);
/**
* Convert the execution to one performed asynchronously on the IsolatedExecutor, returning a Future of the execution result
*/
<I1, I2, I3, O> TriFunction<I1, I2, I3, Future<O>> async(TriFunction<I1, I2, I3, O> f);
/**
* Convert the execution to one performed synchronously on the IsolatedExecutor
*/
<I1, I2, I3, O> TriFunction<I1, I2, I3, O> sync(TriFunction<I1, I2, I3, O> f);
}

View File

@ -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();
}

View File

@ -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<IMessage> 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);
}

View File

@ -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<I extends IInstance> implements ICluster, AutoCloseable
public abstract class AbstractCluster<I extends IInstance> implements ICluster<I>, 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<I extends IInstance> implements ICluster,
// mutated by starting/stopping a node
private final List<I> instances;
private final Map<InetAddressAndPort, I> instanceMap;
private final Map<InetSocketAddress, I> instanceMap;
private final Versions.Version initialVersion;
@ -111,7 +114,7 @@ public abstract class AbstractCluster<I extends IInstance> 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<I extends IInstance> 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<I extends IInstance> implements ICluster,
private IInvokableInstance newInstance(int generation)
{
ClassLoader classLoader = new InstanceClassLoader(generation, config.num, version.classpath, sharedClassLoader);
return Instance.transferAdhoc((SerializableBiFunction<IInstanceConfig, ClassLoader, Instance>) Instance::new, classLoader)
.apply(config.forVersion(version.major), classLoader);
ClassLoader classLoader = new InstanceClassLoader(generation, config.num(), version.classpath, sharedClassLoader);
return Instance.transferAdhoc((SerializableBiFunction<IInstanceConfig, ClassLoader, Instance>)Instance::new, classLoader)
.apply(config.forVersion(version.major), classLoader);
}
public IInstanceConfig config()
@ -158,7 +161,7 @@ public abstract class AbstractCluster<I extends IInstance> 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<I extends IInstance> implements ICluster,
}
}
protected AbstractCluster(File root, Versions.Version initialVersion, List<InstanceConfig> configs,
protected AbstractCluster(File root, Versions.Version initialVersion, List<IInstanceConfig> configs,
ClassLoader sharedClassLoader)
{
this.root = root;
@ -248,27 +251,27 @@ public abstract class AbstractCluster<I extends IInstance> 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<I extends IInstance> 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<I extends IInstance> 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<I extends IInstance> 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<I extends IInstance> 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<I extends IInstance> 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<I extends IInstance> implements ICluster,
get(cl.getInstanceId()).uncaughtException(thread, error);
}
protected interface Factory<I extends IInstance, C extends AbstractCluster<I>>
{
C newCluster(File root, Versions.Version version, List<InstanceConfig> configs, ClassLoader sharedClassLoader);
}
public static class Builder<I extends IInstance, C extends AbstractCluster<I>>
{
private final Factory<I, C> factory;
private int nodeCount;
private int subnet;
private Map<Integer, NetworkTopology.DcAndRack> nodeIdTopology;
private TokenSupplier tokenSupplier;
private File root;
private Versions.Version version = Versions.CURRENT;
private Consumer<InstanceConfig> configUpdater;
public Builder(Factory<I, C> factory)
{
this.factory = factory;
}
public Builder<I, C> withTokenSupplier(TokenSupplier tokenSupplier)
{
this.tokenSupplier = tokenSupplier;
return this;
}
public Builder<I, C> withSubnet(int subnet)
{
this.subnet = subnet;
return this;
}
public Builder<I, C> withNodes(int nodeCount)
{
this.nodeCount = nodeCount;
return this;
}
public Builder<I, C> withDCs(int dcCount)
{
return withRacks(dcCount, 1);
}
public Builder<I, C> 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<I, C> 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<I, C> withDC(String dcName, int nodeCount)
{
return withRack(dcName, rackName(1), nodeCount);
}
public Builder<I, C> 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<I, C> withNodeIdTopology(Map<Integer, NetworkTopology.DcAndRack> 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<I, C> withRoot(File root)
{
this.root = root;
return this;
}
public Builder<I, C> withVersion(Versions.Version version)
{
this.version = version;
return this;
}
public Builder<I, C> withConfig(Consumer<InstanceConfig> 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<InstanceConfig> 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()
{

View File

@ -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<Object[][]> asyncExecuteWithTracing(UUID sessionId, String query, Enum<?> consistencyLevelOrigin, Object... boundValues)
public Future<Object[][]> 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<Object[]> executeWithPaging(String query, Enum<?> consistencyLevelOrigin, int pageSize, Object... boundValues)
public Iterator<Object[]> 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<Object[]>() {
Iterator<Object[]> iter = RowUtil.toObjects(UntypedResultSet.create(selectStatement, consistencyLevel, clientState, pager, pageSize));
Iterator<Object[]> iter = RowUtil.toObjects(UntypedResultSet.create(selectStatement, toCassandraCL(consistencyLevel), clientState, pager, pageSize));
public boolean hasNext()
{

View File

@ -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);
}

View File

@ -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<InetAddressAndPort, InetSocketAddress> cache = new ConcurrentHashMap<>();
private static final Map<InetSocketAddress, InetAddressAndPort> 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<InetAddressAndPort, Map<String, String>> 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

View File

@ -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 <O> CallableNoExcept<Future<O>> asyncCallsOnInstance(SerializableCallable<O> call) { return async(transfer(call)); }
public default <O> CallableNoExcept<O> callsOnInstance(SerializableCallable<O> call) { return sync(transfer(call)); }
public default <O> O callOnInstance(SerializableCallable<O> call) { return callsOnInstance(call).call(); }
public default CallableNoExcept<Future<?>> 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 <I> Function<I, Future<?>> asyncAcceptsOnInstance(SerializableConsumer<I> consumer) { return async(transfer(consumer)); }
public default <I> Consumer<I> acceptsOnInstance(SerializableConsumer<I> consumer) { return sync(transfer(consumer)); }
public default <I1, I2> BiFunction<I1, I2, Future<?>> asyncAcceptsOnInstance(SerializableBiConsumer<I1, I2> consumer) { return async(transfer(consumer)); }
public default <I1, I2> BiConsumer<I1, I2> acceptsOnInstance(SerializableBiConsumer<I1, I2> consumer) { return sync(transfer(consumer)); }
public default <I, O> Function<I, Future<O>> asyncAppliesOnInstance(SerializableFunction<I, O> f) { return async(transfer(f)); }
public default <I, O> Function<I, O> appliesOnInstance(SerializableFunction<I, O> f) { return sync(transfer(f)); }
public default <I1, I2, O> BiFunction<I1, I2, Future<O>> asyncAppliesOnInstance(SerializableBiFunction<I1, I2, O> f) { return async(transfer(f)); }
public default <I1, I2, O> BiFunction<I1, I2, O> appliesOnInstance(SerializableBiFunction<I1, I2, O> f) { return sync(transfer(f)); }
public default <I1, I2, I3, O> TriFunction<I1, I2, I3, Future<O>> asyncAppliesOnInstance(SerializableTriFunction<I1, I2, I3, O> f) { return async(transfer(f)); }
public default <I1, I2, I3, O> TriFunction<I1, I2, I3, O> appliesOnInstance(SerializableTriFunction<I1, I2, I3, O> f) { return sync(transfer(f)); }
public <E extends Serializable> E transfer(E object);
}

View File

@ -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);
}

View File

@ -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<Class<?>, Function<Object, Object>> mapper = new HashMap<Class<?>, Function<Object, Object>>() {{
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<String> initialTokens = new ArrayList<>();
List<InetAddressAndPort> hosts = new ArrayList<>();
List<InetSocketAddress> hosts = new ArrayList<>();
List<UUID> 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<Notification> notifications = new CopyOnWriteArrayList<>();
private static final class CollectingNotificationListener implements NotificationListener
{
private final List<Notification> notifications = new CopyOnWriteArrayList<>();
public void handleNotification(Notification notification, Object handback)
{

View File

@ -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<String> 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<String> 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<String> 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();
}
}

View File

@ -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<Class<?>, Function<Object, Object>> mapping)
{
for (Map.Entry<String, Object> 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<Class<?>, Function<Object, Object>> 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)

View File

@ -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 <O> Supplier<Future<O>> supplyAsync(SerializableSupplier<O> call) { return () -> isolatedExecutor.submit(call::get); }
public <O> Supplier<O> supplySync(SerializableSupplier<O> call) { return () -> waitOn(supplyAsync(call).get()); }
public <O> CallableNoExcept<Future<O>> async(CallableNoExcept<O> call) { return () -> isolatedExecutor.submit(call); }
public <O> CallableNoExcept<O> sync(CallableNoExcept<O> call) { return () -> waitOn(async(call).call()); }

View File

@ -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<Filter> inboundFilters = new CopyOnWriteArrayList<>();
private final List<Filter> 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<Filter> 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<Filter> parent;
final int[] from;
final int[] to;
final int[] verbs;
final Matcher matcher;
private Filter(List<Filter> 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();
}
}

View File

@ -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;
}

View File

@ -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<InetAddressAndPort, DcAndRack> 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<Integer, DcAndRack> 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<Integer, NetworkTopology.DcAndRack> singleDcNetworkTopology(int nodeCount,
String dc,
String rack)
{
return networkTopology(nodeCount, (nodeid) -> NetworkTopology.dcAndRack(dc, rack));
}
public static Map<Integer, NetworkTopology.DcAndRack> networkTopology(int nodeCount,
IntFunction<DcAndRack> dcAndRackSupplier)
{
return IntStream.rangeClosed(1, nodeCount).boxed()
.collect(Collectors.toMap(nodeId -> nodeId,
dcAndRackSupplier::apply));
}
}

View File

@ -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;
/**

View File

@ -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<Major, List<Version>> versions;
public Versions(Map<Major, List<Version>> 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-(?<fullversion>(\\d+)\\.(\\d+)(\\.\\d+)?(\\.\\d+)?)([~\\-]\\w[.\\w]*(?:\\-\\w[.\\w]*)*)?(\\+[.\\w]+)?\\.jar");
final Map<Major, List<Version>> 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<Major, List<Version>> 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);
}
}
}

View File

@ -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;
}
}

View File

@ -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<IInvokableInstance, Cluster> builder = Cluster.build(originalNodeCount)
.withTokenSupplier(Cluster.evenlyDistributedTokens(expandedNodeCount))
.withNodeIdTopology(NetworkTopology.singleDcNetworkTopology(originalNodeCount, "dc0", "rack0"))
.withConfig(config -> config.with(NETWORK, GOSSIP));
Builder<IInstance, ICluster> builder = builder().withNodes(originalNodeCount)
.withTokenSupplier(TokenSupplier.evenlyDistributedTokens(expandedNodeCount))
.withNodeIdTopology(NetworkTopology.singleDcNetworkTopology(originalNodeCount, "dc0", "rack0"))
.withConfig(config -> config.with(NETWORK, GOSSIP));
Map<Integer, Long> withBootstrap = null;
Map<Integer, Long> naturally = null;
try (Cluster cluster = builder.start())
try (ICluster<IInvokableInstance> 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<Integer, Long> 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<Integer, Long> count(Cluster cluster)
public Map<Integer, Long> 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]));
}
}
}

View File

@ -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<Integer> contendingNodes,
Consumer<Cluster> setupForEachRound,
Consumer<ICluster> setupForEachRound,
Function<AtomicReference<Throwable>, Boolean> expectedException,
String assertHintMessage) throws InterruptedException
{

View File

@ -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;

View File

@ -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 extends AbstractCluster<?>> C init(C cluster)
{
return init(cluster, cluster.size());
}
protected static <C extends AbstractCluster<?>> 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<Object[]> actual, Iterator<Object[]> 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<Object[]> 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<Object[]> iter)
{
List<Object[]> 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;
}
}

View File

@ -16,7 +16,7 @@
* limitations under the License.
*/
package org.apache.cassandra.distributed.impl;
package org.apache.cassandra.distributed.test;
import java.io.Serializable;

View File

@ -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<IInvokableInstance> 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)

View File

@ -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())
{
}
}

View File

@ -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);
}
}
}

View File

@ -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<IInvokableInstance> 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<Integer> outboundMessagesSeen = new HashSet<>();
Set<Integer> inboundMessagesSeen = new HashSet<>();

View File

@ -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<InetAddress,Integer> forwardFromCounts = new HashMap<>();
Map<InetAddress,Integer> commitCounts = new HashMap<>();
Map<InetAddress, Integer> forwardFromCounts = new HashMap<>();
Map<InetAddress, Integer> 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<Future<Object[][]>> 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<Future<Object[][]>> 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<TracingUtil.TraceEntry> 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);
}
}
}
}

View File

@ -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();

View File

@ -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<IInvokableInstance> 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")));
}
}
}

View File

@ -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"));

View File

@ -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<Boolean, Boolean> 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<Pair<Boolean, Boolean>> rsFuture = es.submit(() -> cluster.get(1).callOnInstance(repair(options(true))));
Future<RepairResult> 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<Boolean, Boolean> 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<Pair<Boolean, Boolean>> repairStatusFuture = es.submit(() -> cluster.get(1).callOnInstance(repair(options(true, localRanges.get(0)))));
Future<RepairResult> 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<Boolean, Boolean> 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<Pair<Boolean, Boolean>> repair(Map<String, String> options)
private static IIsolatedExecutor.SerializableCallable<RepairResult> repair(Map<String, String> 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());
};
}

View File

@ -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<IInvokableInstance> 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<String> hosts = cluster.stream()
.map(i -> i.config().broadcastAddressAndPort().address.getHostAddress())
.map(i -> i.config().broadcastAddress().getAddress().getHostAddress())
.collect(Collectors.toList());
final int queriesCount = 3;

View File

@ -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<Token> 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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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(() -> {

View File

@ -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<IInvokableInstance> cluster;
private static void insert(ICluster<IInvokableInstance> 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<IInvokableInstance> 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<IInvokableInstance> cluster, int ... nodes)
{
for (int node : nodes)
cluster.get(node).runOnInstance(rethrow(() -> StorageService.instance.forceKeyspaceFlush(KEYSPACE)));
}
private static Cluster create(Consumer<InstanceConfig> configModifier) throws IOException
private static ICluster create(Consumer<IInstanceConfig> 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<String, String> options)
private void repair(ICluster<IInvokableInstance> cluster, Map<String, String> 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<IInvokableInstance> 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<IInvokableInstance> 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}");
}

View File

@ -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<InstanceConfig> updater) throws Throwable
void doTest(int numClusterNodes, Consumer<IInstanceConfig> 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));

View File

@ -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<IInvokableInstance> 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);
}
}

View File

@ -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));

View File

@ -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 <I extends IInstance, C extends ICluster> Builder<I, C> 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<I, C>) Cluster.build();
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -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 <I extends IInstance, C extends ICluster> Builder<I, C> builder()
{
return (Builder<I, C>) UpgradeableCluster.build();
}
public static interface RunOnCluster
{
public void run(UpgradeableCluster cluster) throws Throwable;

View File

@ -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

View File

@ -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

View File

@ -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",