/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.elasticsearch.test.cluster;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledFuture;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.UntypedResultSet;
import org.apache.cassandra.cql3.UntypedResultSet.Row;
import org.apache.cassandra.db.ConsistencyLevel;
import org.apache.cassandra.dht.Range;
import org.apache.cassandra.dht.Token;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.exceptions.RequestExecutionException;
import org.apache.cassandra.exceptions.RequestValidationException;
import org.apache.cassandra.service.ClientState;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.elassandra.NoPersistedMetaDataException;
import org.elassandra.cluster.routing.AbstractSearchStrategy;
import org.elassandra.cluster.routing.AbstractSearchStrategy.Router;
import org.elassandra.cluster.routing.PrimaryFirstSearchStrategy.PrimaryFirstRouter;
import org.elassandra.index.search.TokenRangesService;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionWriteResponse.ShardInfo;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterService;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateListener;
import org.elasticsearch.cluster.ClusterStateTaskConfig;
import org.elasticsearch.cluster.ClusterStateTaskExecutor;
import org.elasticsearch.cluster.ClusterStateTaskListener;
import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.cluster.LocalNodeMasterListener;
import org.elasticsearch.cluster.TimeoutClusterStateListener;
import org.elasticsearch.cluster.block.ClusterBlock;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.routing.OperationRouting;
import org.elasticsearch.cluster.routing.ShardRoutingState;
import org.elasticsearch.cluster.routing.allocation.decider.AwarenessAllocationDecider;
import org.elasticsearch.cluster.service.PendingClusterTask;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.component.Lifecycle;
import org.elasticsearch.common.component.LifecycleListener;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.DummyTransportAddress;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
import org.elasticsearch.common.util.concurrent.FutureUtils;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.engine.Engine.GetResult;
import org.elasticsearch.index.get.GetField;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.Uid;
import org.elasticsearch.index.percolator.PercolatorQueriesRegistry;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.tasks.TaskManager;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
/** a class that simulate simple cluster service features, like state storage and listeners */
public class TestClusterService implements ClusterService {
volatile ClusterState state;
private volatile TaskManager taskManager;
private final List<ClusterStateListener> listeners = new CopyOnWriteArrayList<>();
private final Queue<NotifyTimeout> onGoingTimeouts = ConcurrentCollections.newQueue();
private final ThreadPool threadPool;
private final ESLogger logger = Loggers.getLogger(getClass(), Settings.EMPTY);
private final OperationRouting operationRouting = new OperationRouting(Settings.Builder.EMPTY_SETTINGS, new AwarenessAllocationDecider(), this);
public TestClusterService() {
this(ClusterState.builder(new ClusterName("test")).build());
}
public TestClusterService(ThreadPool threadPool) {
this(ClusterState.builder(new ClusterName("test")).build(), threadPool);
taskManager = new TaskManager(Settings.EMPTY);
}
public TestClusterService(ThreadPool threadPool, TransportService transportService) {
this(ClusterState.builder(new ClusterName("test")).build(), threadPool);
taskManager = transportService.getTaskManager();
}
public TestClusterService(ClusterState state) {
this(state, null);
}
public TestClusterService(ClusterState state, @Nullable ThreadPool threadPool) {
if (state.getNodes().size() == 0) {
state = ClusterState.builder(state).nodes(
DiscoveryNodes.builder()
.put(new DiscoveryNode("test_node", DummyTransportAddress.INSTANCE, Version.CURRENT))
.localNodeId("test_node")).build();
}
assert state.getNodes().localNode() != null;
this.state = state;
this.threadPool = threadPool;
}
/** set the current state and trigger any registered listeners about the change, mimicking an update task */
synchronized public ClusterState setState(ClusterState state) {
assert state.getNodes().localNode() != null;
// make sure we have a version increment
state = ClusterState.builder(state).version(this.state.version() + 1).build();
return setStateAndNotifyListeners(state);
}
private ClusterState setStateAndNotifyListeners(ClusterState state) {
ClusterChangedEvent event = new ClusterChangedEvent("test", state, this.state);
this.state = state;
for (ClusterStateListener listener : listeners) {
listener.clusterChanged(event);
}
return state;
}
/** set the current state and trigger any registered listeners about the change */
public ClusterState setState(ClusterState.Builder state) {
return setState(state.build());
}
@Override
public DiscoveryNode localNode() {
return state.getNodes().localNode();
}
@Override
public ClusterState state() {
return state;
}
@Override
public void addInitialStateBlock(ClusterBlock block) throws IllegalStateException {
throw new UnsupportedOperationException();
}
@Override
public void removeInitialStateBlock(ClusterBlock block) throws IllegalStateException {
throw new UnsupportedOperationException();
}
@Override
public OperationRouting operationRouting() {
return operationRouting;
}
@Override
public void addFirst(ClusterStateListener listener) {
listeners.add(0, listener);
}
@Override
public void addLast(ClusterStateListener listener) {
listeners.add(listener);
}
@Override
public void add(ClusterStateListener listener) {
listeners.add(listener);
}
@Override
public void remove(ClusterStateListener listener) {
listeners.remove(listener);
for (Iterator<NotifyTimeout> it = onGoingTimeouts.iterator(); it.hasNext(); ) {
NotifyTimeout timeout = it.next();
if (timeout.listener.equals(listener)) {
timeout.cancel();
it.remove();
}
}
}
@Override
public void add(LocalNodeMasterListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void remove(LocalNodeMasterListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void add(final TimeValue timeout, final TimeoutClusterStateListener listener) {
if (threadPool == null) {
throw new UnsupportedOperationException("TestClusterService wasn't initialized with a thread pool");
}
NotifyTimeout notifyTimeout = new NotifyTimeout(listener, timeout);
notifyTimeout.future = threadPool.schedule(timeout, ThreadPool.Names.GENERIC, notifyTimeout);
onGoingTimeouts.add(notifyTimeout);
listeners.add(listener);
listener.postAdded();
}
@Override
public void submitStateUpdateTask(String source, ClusterStateUpdateTask updateTask) {
submitStateUpdateTask(source, null, updateTask, updateTask, updateTask);
}
@Override
synchronized public <T> void submitStateUpdateTask(final String source, T task, ClusterStateTaskConfig config, ClusterStateTaskExecutor<T> executor, final ClusterStateTaskListener listener) {
logger.debug("processing [{}]", source);
if (state().nodes().localNodeMaster() == false && executor.runOnlyOnMaster()) {
listener.onNoLongerMaster(source);
logger.debug("failed [{}], no longer master", source);
return;
}
ClusterStateTaskExecutor.BatchResult<T> batchResult;
ClusterState previousClusterState = state;
try {
batchResult = executor.execute(previousClusterState, Arrays.asList(task));
} catch (Exception e) {
batchResult = ClusterStateTaskExecutor.BatchResult.<T>builder().failure(task, e).build(previousClusterState, config.doPresistMetaData());
}
batchResult.executionResults.get(task).handle(
new Runnable() {
@Override
public void run() {
}
},
new ClusterStateTaskExecutor.TaskResult.FailureConsumer() {
@Override
public void accept(Throwable ex) {
listener.onFailure(source, new ElasticsearchException("failed to process cluster state update task [" + source + "]", ex));
}
}
);
setStateAndNotifyListeners(batchResult.resultingState);
listener.clusterStateProcessed(source, previousClusterState, batchResult.resultingState);
logger.debug("finished [{}]", source);
}
@Override
public TimeValue getMaxTaskWaitTime() {
throw new UnsupportedOperationException();
}
@Override
public TaskManager getTaskManager() {
return taskManager;
}
@Override
public List<PendingClusterTask> pendingTasks() {
throw new UnsupportedOperationException();
}
@Override
public int numberOfPendingTasks() {
throw new UnsupportedOperationException();
}
@Override
public Lifecycle.State lifecycleState() {
throw new UnsupportedOperationException();
}
@Override
public void addLifecycleListener(LifecycleListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void removeLifecycleListener(LifecycleListener listener) {
throw new UnsupportedOperationException();
}
@Override
public ClusterService start() throws ElasticsearchException {
throw new UnsupportedOperationException();
}
@Override
public ClusterService stop() throws ElasticsearchException {
throw new UnsupportedOperationException();
}
@Override
public void close() throws ElasticsearchException {
throw new UnsupportedOperationException();
}
class NotifyTimeout implements Runnable {
final TimeoutClusterStateListener listener;
final TimeValue timeout;
volatile ScheduledFuture future;
NotifyTimeout(TimeoutClusterStateListener listener, TimeValue timeout) {
this.listener = listener;
this.timeout = timeout;
}
public void cancel() {
FutureUtils.cancel(future);
}
@Override
public void run() {
if (future != null && future.isCancelled()) {
return;
}
listener.onTimeout(this.timeout);
// note, we rely on the listener to remove itself in case of timeout if needed
}
}
@Override
public IndexService indexService(String index) {
// TODO Auto-generated method stub
return null;
}
@Override
public IndexService indexServiceSafe(String index) {
// TODO Auto-generated method stub
return null;
}
@Override
public AbstractSearchStrategy searchStrategy(IndexMetaData indexMetaData, ClusterState clusterState) {
// TODO Auto-generated method stub
return null;
}
@Override
public Router getRouter(IndexMetaData indexMetaData, ClusterState state) {
// TODO Auto-generated method stub
return null;
}
@Override
public PrimaryFirstRouter updateRouter(IndexMetaData indexMetaData, ClusterState state) {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<String, GetField> flattenGetField(String[] fieldFilter, String path, Object node,
Map<String, GetField> flatFields) {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<String, List<Object>> flattenTree(Set<String> neededFiedls, String path, Object node,
Map<String, List<Object>> fields) {
// TODO Auto-generated method stub
return null;
}
@Override
public void createOrUpdateElasticAdminKeyspace() {
// TODO Auto-generated method stub
}
@Override
public void createIndexKeyspace(String index, int replicationFactor) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void createSecondaryIndices(IndexMetaData indexMetaData) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void dropSecondaryIndices(IndexMetaData indexMetaData) throws RequestExecutionException {
// TODO Auto-generated method stub
}
@Override
public DocPrimaryKey parseElasticId(String index, String cfName, String id)
throws JsonParseException, JsonMappingException, IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public ClusterState updateNumberOfShards(ClusterState currentState) {
// TODO Auto-generated method stub
return null;
}
@Override
public void submitNumberOfShardsUpdate() {
// TODO Auto-generated method stub
}
@Override
public void updateRoutingTable() {
// TODO Auto-generated method stub
}
@Override
public boolean isStaticDocument(String index, Uid uid)
throws JsonParseException, JsonMappingException, IOException {
// TODO Auto-generated method stub
return false;
}
@Override
public GetResult fetchSourceInternal(String ksName, String index, String type, String id) throws IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<String, Object> rowAsMap(String index, String type, Row row) throws IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public int rowAsMap(String index, String type, Row row, Map<String, Object> map) throws IOException {
// TODO Auto-generated method stub
return 0;
}
@Override
public Object[] rowAsArray(String index, String type, Row row) throws IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public Object[] rowAsArray(String index, String type, Row row, boolean valueForSearch) throws IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public void deleteRow(String index, String type, String id, ConsistencyLevel cl)
throws InvalidRequestException, RequestExecutionException, RequestValidationException, IOException {
// TODO Auto-generated method stub
}
@Override
public void blockingMappingUpdate(IndexService indexService, String type, String source) throws Exception {
// TODO Auto-generated method stub
}
@Override
public void writeMetaDataAsComment(String metaDataString) throws ConfigurationException, IOException {
// TODO Auto-generated method stub
}
@Override
public MetaData readMetaDataAsComment() throws NoPersistedMetaDataException {
// TODO Auto-generated method stub
return null;
}
@Override
public MetaData readMetaDataAsRow(ConsistencyLevel cl) throws NoPersistedMetaDataException {
// TODO Auto-generated method stub
return null;
}
@Override
public void persistMetaData(MetaData currentMetadData, MetaData newMetaData, String source)
throws ConfigurationException, IOException, InvalidRequestException, RequestExecutionException,
RequestValidationException {
// TODO Auto-generated method stub
}
@Override
public MetaData checkForNewMetaData(Long version) throws NoPersistedMetaDataException {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<UUID, ShardRoutingState> getShardRoutingStates(String index) {
// TODO Auto-generated method stub
return null;
}
@Override
public void putShardRoutingState(String index, ShardRoutingState shardRoutingState)
throws JsonGenerationException, JsonMappingException, IOException {
// TODO Auto-generated method stub
}
@Override
public boolean isDatacenterGroupMember(InetAddress endpoint) {
// TODO Auto-generated method stub
return false;
}
@Override
public ShardInfo shardInfo(String index, ConsistencyLevel cl) {
// TODO Auto-generated method stub
return null;
}
@Override
public Settings settings() {
return null;
}
@Override
public void dropIndexKeyspace(String ksName) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void createSecondaryIndex(String ksName, MappingMetaData mapping, String className) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void dropSecondaryIndex(String ksName, String cfName) throws RequestExecutionException {
// TODO Auto-generated method stub
}
@Override
public void dropTable(String ksName, String cfName) throws RequestExecutionException {
// TODO Auto-generated method stub
}
@Override
public void updateTableSchema(IndexService indexService, MappingMetaData mappingMd) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void publishGossipStates() {
// TODO Auto-generated method stub
}
@Override
public void updateDocument(IndicesService indicesService, IndexRequest request, IndexMetaData indexMetaData)
throws Exception {
// TODO Auto-generated method stub
}
@Override
public void insertDocument(IndicesService indicesService, IndexRequest request, IndexMetaData indexMetaData)
throws Exception {
// TODO Auto-generated method stub
}
@Override
public void addPost(ClusterStateListener listener) {
// TODO Auto-generated method stub
}
@Override
public BytesReference source(DocumentMapper docMapper, Map sourceAsMap, String index, Uid uid)
throws JsonParseException, JsonMappingException, IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public BytesReference source(DocumentMapper docMapper, Map sourceAsMap, String index, String type, String id)
throws JsonParseException, JsonMappingException, IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public void addShardStartedBarrier() {
// TODO Auto-generated method stub
}
@Override
public void removeShardStartedBarrier() {
// TODO Auto-generated method stub
}
@Override
public void blockUntilShardsStarted() {
// TODO Auto-generated method stub
}
@Override
public void dropSecondaryIndex(CFMetaData cfMetaData) throws RequestExecutionException {
// TODO Auto-generated method stub
}
@Override
public boolean rowExists(MapperService mapperService, String type, String id)
throws InvalidRequestException, RequestExecutionException, RequestValidationException, IOException {
// TODO Auto-generated method stub
return false;
}
@Override
public UntypedResultSet fetchRow(String ksName, String index, String type, String id, String[] columns,
Map<String, ColumnDefinition> columnDefs)
throws InvalidRequestException, RequestExecutionException, RequestValidationException, IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public UntypedResultSet fetchRow(String ksName, String index, String cfName, String id, String[] columns,
ConsistencyLevel cl, Map<String, ColumnDefinition> columnDefs)
throws InvalidRequestException, RequestExecutionException, RequestValidationException, IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public UntypedResultSet fetchRow(String ksName, String index, String cfName, DocPrimaryKey docPk, String[] columns,
ConsistencyLevel cl, Map<String, ColumnDefinition> columnDefs)
throws InvalidRequestException, RequestExecutionException, RequestValidationException, IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public String buildFetchQuery(String ksName, String index, String cfName, String[] requiredColumns,
boolean forStaticDocument, Map<String, ColumnDefinition> columnDefs)
throws ConfigurationException, IndexNotFoundException, IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public UntypedResultSet fetchRowInternal(String ksName, String index, String cfName, String id, String[] columns,
Map<String, ColumnDefinition> columnDefs) throws ConfigurationException, IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public UntypedResultSet fetchRowInternal(String ksName, String index, String cfName, DocPrimaryKey docPk,
String[] columns, Map<String, ColumnDefinition> columnDefs) throws ConfigurationException, IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public UntypedResultSet fetchRowInternal(String ksName, String index, String cfName, String[] columns,
Object[] pkColumns, boolean forStaticDocument, Map<String, ColumnDefinition> columnDefs)
throws ConfigurationException, IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public UntypedResultSet process(ConsistencyLevel cl, ClientState clientState, String query)
throws RequestExecutionException, RequestValidationException, InvalidRequestException {
// TODO Auto-generated method stub
return null;
}
@Override
public UntypedResultSet process(ConsistencyLevel cl, ClientState clientState, String query, Object... values)
throws RequestExecutionException, RequestValidationException, InvalidRequestException {
// TODO Auto-generated method stub
return null;
}
@Override
public String getElasticAdminKeyspaceName() {
// TODO Auto-generated method stub
return null;
}
@Override
public int getLocalDataCenterSize() {
// TODO Auto-generated method stub
return 0;
}
@Override
public TokenRangesService getTokenRangesService() {
// TODO Auto-generated method stub
return null;
}
@Override
public void updateMapping(String ksName, MappingMetaData mapping) {
// TODO Auto-generated method stub
}
@Override
public void recoverShard(String index) {
// TODO Auto-generated method stub
}
}