use of org.opensearch.cluster.ClusterStateUpdateTask in project OpenSearch by opensearch-project.
the class BlockMasterServiceOnMaster method startDisrupting.
@Override
public void startDisrupting() {
disruptedNode = cluster.getMasterName();
final String disruptionNodeCopy = disruptedNode;
if (disruptionNodeCopy == null) {
return;
}
ClusterService clusterService = cluster.getInstance(ClusterService.class, disruptionNodeCopy);
if (clusterService == null) {
return;
}
logger.info("blocking master service on node [{}]", disruptionNodeCopy);
boolean success = disruptionLatch.compareAndSet(null, new CountDownLatch(1));
assert success : "startDisrupting called without waiting on stopDisrupting to complete";
final CountDownLatch started = new CountDownLatch(1);
clusterService.getMasterService().submitStateUpdateTask("service_disruption_block", new ClusterStateUpdateTask() {
@Override
public Priority priority() {
return Priority.IMMEDIATE;
}
@Override
public ClusterState execute(ClusterState currentState) throws Exception {
started.countDown();
CountDownLatch latch = disruptionLatch.get();
if (latch != null) {
try {
latch.await();
} catch (InterruptedException e) {
Throwables.rethrow(e);
}
}
return currentState;
}
@Override
public void onFailure(String source, Exception e) {
logger.error("unexpected error during disruption", e);
}
});
try {
started.await();
} catch (InterruptedException e) {
}
}
use of org.opensearch.cluster.ClusterStateUpdateTask in project OpenSearch by opensearch-project.
the class FakeThreadPoolMasterServiceTests method testFakeMasterService.
public void testFakeMasterService() {
List<Runnable> runnableTasks = new ArrayList<>();
AtomicReference<ClusterState> lastClusterStateRef = new AtomicReference<>();
DiscoveryNode discoveryNode = new DiscoveryNode("node", OpenSearchTestCase.buildNewFakeTransportAddress(), Collections.emptyMap(), new HashSet<>(DiscoveryNodeRole.BUILT_IN_ROLES), Version.CURRENT);
lastClusterStateRef.set(ClusterStateCreationUtils.state(discoveryNode, discoveryNode));
long firstClusterStateVersion = lastClusterStateRef.get().version();
AtomicReference<ActionListener<Void>> publishingCallback = new AtomicReference<>();
final ThreadContext context = new ThreadContext(Settings.EMPTY);
final ThreadPool mockThreadPool = mock(ThreadPool.class);
when(mockThreadPool.getThreadContext()).thenReturn(context);
final ExecutorService executorService = mock(ExecutorService.class);
doAnswer(invocationOnMock -> runnableTasks.add((Runnable) invocationOnMock.getArguments()[0])).when(executorService).execute(any());
when(mockThreadPool.generic()).thenReturn(executorService);
FakeThreadPoolMasterService masterService = new FakeThreadPoolMasterService("test_node", "test", mockThreadPool, runnableTasks::add);
masterService.setClusterStateSupplier(lastClusterStateRef::get);
masterService.setClusterStatePublisher((event, publishListener, ackListener) -> {
lastClusterStateRef.set(event.state());
publishingCallback.set(publishListener);
});
masterService.start();
AtomicBoolean firstTaskCompleted = new AtomicBoolean();
masterService.submitStateUpdateTask("test1", new ClusterStateUpdateTask() {
@Override
public ClusterState execute(ClusterState currentState) {
return ClusterState.builder(currentState).metadata(Metadata.builder(currentState.metadata()).put(indexBuilder("test1"))).build();
}
@Override
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
assertFalse(firstTaskCompleted.get());
firstTaskCompleted.set(true);
}
@Override
public void onFailure(String source, Exception e) {
throw new AssertionError();
}
});
assertThat(runnableTasks.size(), equalTo(1));
assertThat(lastClusterStateRef.get().metadata().indices().size(), equalTo(0));
assertThat(lastClusterStateRef.get().version(), equalTo(firstClusterStateVersion));
assertNull(publishingCallback.get());
assertFalse(firstTaskCompleted.get());
final Runnable scheduleTask = runnableTasks.remove(0);
assertThat(scheduleTask, hasToString("master service scheduling next task"));
scheduleTask.run();
final Runnable publishTask = runnableTasks.remove(0);
assertThat(publishTask, hasToString(containsString("publish change of cluster state")));
publishTask.run();
assertThat(lastClusterStateRef.get().metadata().indices().size(), equalTo(1));
assertThat(lastClusterStateRef.get().version(), equalTo(firstClusterStateVersion + 1));
assertNotNull(publishingCallback.get());
assertFalse(firstTaskCompleted.get());
assertThat(runnableTasks.size(), equalTo(0));
AtomicBoolean secondTaskCompleted = new AtomicBoolean();
masterService.submitStateUpdateTask("test2", new ClusterStateUpdateTask() {
@Override
public ClusterState execute(ClusterState currentState) {
return ClusterState.builder(currentState).metadata(Metadata.builder(currentState.metadata()).put(indexBuilder("test2"))).build();
}
@Override
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
assertFalse(secondTaskCompleted.get());
secondTaskCompleted.set(true);
}
@Override
public void onFailure(String source, Exception e) {
throw new AssertionError();
}
});
assertThat(runnableTasks.size(), equalTo(0));
publishingCallback.getAndSet(null).onResponse(null);
assertTrue(firstTaskCompleted.get());
// check that new task gets queued
assertThat(runnableTasks.size(), equalTo(1));
// schedule again
runnableTasks.remove(0).run();
// publish again
runnableTasks.remove(0).run();
assertThat(lastClusterStateRef.get().metadata().indices().size(), equalTo(2));
assertThat(lastClusterStateRef.get().version(), equalTo(firstClusterStateVersion + 2));
assertNotNull(publishingCallback.get());
assertFalse(secondTaskCompleted.get());
publishingCallback.getAndSet(null).onResponse(null);
assertTrue(secondTaskCompleted.get());
// check that no more tasks are queued
assertThat(runnableTasks.size(), equalTo(0));
}
use of org.opensearch.cluster.ClusterStateUpdateTask in project OpenSearch by opensearch-project.
the class DynamicMappingIT method testPreflightCheckAvoidsMaster.
public void testPreflightCheckAvoidsMaster() throws InterruptedException {
createIndex("index", Settings.builder().put(INDEX_MAPPING_TOTAL_FIELDS_LIMIT_SETTING.getKey(), 2).build());
ensureGreen("index");
client().prepareIndex("index").setId("1").setSource("field1", "value1").get();
final CountDownLatch masterBlockedLatch = new CountDownLatch(1);
final CountDownLatch indexingCompletedLatch = new CountDownLatch(1);
internalCluster().getInstance(ClusterService.class, internalCluster().getMasterName()).submitStateUpdateTask("block-state-updates", new ClusterStateUpdateTask() {
@Override
public ClusterState execute(ClusterState currentState) throws Exception {
masterBlockedLatch.countDown();
indexingCompletedLatch.await();
return currentState;
}
@Override
public void onFailure(String source, Exception e) {
throw new AssertionError("unexpected", e);
}
});
masterBlockedLatch.await();
final IndexRequestBuilder indexRequestBuilder = client().prepareIndex("index").setId("2").setSource("field2", "value2");
try {
assertThat(expectThrows(IllegalArgumentException.class, () -> indexRequestBuilder.get(TimeValue.timeValueSeconds(10))).getMessage(), Matchers.containsString("Limit of total fields [2] has been exceeded"));
} finally {
indexingCompletedLatch.countDown();
}
}
use of org.opensearch.cluster.ClusterStateUpdateTask in project OpenSearch by opensearch-project.
the class TransportAddVotingConfigExclusionsAction method masterOperation.
@Override
protected void masterOperation(AddVotingConfigExclusionsRequest request, ClusterState state, ActionListener<AddVotingConfigExclusionsResponse> listener) throws Exception {
resolveVotingConfigExclusionsAndCheckMaximum(request, state, maxVotingConfigExclusions);
// throws IAE if no nodes matched or maximum exceeded
clusterService.submitStateUpdateTask("add-voting-config-exclusions", new ClusterStateUpdateTask(Priority.URGENT) {
private Set<VotingConfigExclusion> resolvedExclusions;
@Override
public ClusterState execute(ClusterState currentState) {
assert resolvedExclusions == null : resolvedExclusions;
final int finalMaxVotingConfigExclusions = TransportAddVotingConfigExclusionsAction.this.maxVotingConfigExclusions;
resolvedExclusions = resolveVotingConfigExclusionsAndCheckMaximum(request, currentState, finalMaxVotingConfigExclusions);
final CoordinationMetadata.Builder builder = CoordinationMetadata.builder(currentState.coordinationMetadata());
resolvedExclusions.forEach(builder::addVotingConfigExclusion);
final Metadata newMetadata = Metadata.builder(currentState.metadata()).coordinationMetadata(builder.build()).build();
final ClusterState newState = ClusterState.builder(currentState).metadata(newMetadata).build();
assert newState.getVotingConfigExclusions().size() <= finalMaxVotingConfigExclusions;
return newState;
}
@Override
public void onFailure(String source, Exception e) {
listener.onFailure(e);
}
@Override
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
final ClusterStateObserver observer = new ClusterStateObserver(clusterService, request.getTimeout(), logger, threadPool.getThreadContext());
final Set<String> excludedNodeIds = resolvedExclusions.stream().map(VotingConfigExclusion::getNodeId).collect(Collectors.toSet());
final Predicate<ClusterState> allNodesRemoved = clusterState -> {
final Set<String> votingConfigNodeIds = clusterState.getLastCommittedConfiguration().getNodeIds();
return excludedNodeIds.stream().noneMatch(votingConfigNodeIds::contains);
};
final Listener clusterStateListener = new Listener() {
@Override
public void onNewClusterState(ClusterState state) {
listener.onResponse(new AddVotingConfigExclusionsResponse());
}
@Override
public void onClusterServiceClose() {
listener.onFailure(new OpenSearchException("cluster service closed while waiting for voting config exclusions " + resolvedExclusions + " to take effect"));
}
@Override
public void onTimeout(TimeValue timeout) {
listener.onFailure(new OpenSearchTimeoutException("timed out waiting for voting config exclusions " + resolvedExclusions + " to take effect"));
}
};
if (allNodesRemoved.test(newState)) {
clusterStateListener.onNewClusterState(newState);
} else {
observer.waitForNextChange(clusterStateListener, allNodesRemoved);
}
}
});
}
use of org.opensearch.cluster.ClusterStateUpdateTask in project OpenSearch by opensearch-project.
the class TransportClusterHealthAction method waitForEventsAndExecuteHealth.
private void waitForEventsAndExecuteHealth(final ClusterHealthRequest request, final ActionListener<ClusterHealthResponse> listener, final int waitCount, final long endTimeRelativeMillis) {
assert request.waitForEvents() != null;
if (request.local()) {
clusterService.submitStateUpdateTask("cluster_health (wait_for_events [" + request.waitForEvents() + "])", new LocalClusterUpdateTask(request.waitForEvents()) {
@Override
public ClusterTasksResult<LocalClusterUpdateTask> execute(ClusterState currentState) {
return unchanged();
}
@Override
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
final long timeoutInMillis = Math.max(0, endTimeRelativeMillis - threadPool.relativeTimeInMillis());
final TimeValue newTimeout = TimeValue.timeValueMillis(timeoutInMillis);
request.timeout(newTimeout);
executeHealth(request, clusterService.state(), listener, waitCount, observedState -> waitForEventsAndExecuteHealth(request, listener, waitCount, endTimeRelativeMillis));
}
@Override
public void onFailure(String source, Exception e) {
logger.error(() -> new ParameterizedMessage("unexpected failure during [{}]", source), e);
listener.onFailure(e);
}
});
} else {
final TimeValue taskTimeout = TimeValue.timeValueMillis(Math.max(0, endTimeRelativeMillis - threadPool.relativeTimeInMillis()));
clusterService.submitStateUpdateTask("cluster_health (wait_for_events [" + request.waitForEvents() + "])", new ClusterStateUpdateTask(request.waitForEvents()) {
@Override
public ClusterState execute(ClusterState currentState) {
return currentState;
}
@Override
public TimeValue timeout() {
return taskTimeout;
}
@Override
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
final long timeoutInMillis = Math.max(0, endTimeRelativeMillis - threadPool.relativeTimeInMillis());
final TimeValue newTimeout = TimeValue.timeValueMillis(timeoutInMillis);
request.timeout(newTimeout);
// we must use the state from the applier service, because if the state-not-recovered block is in place then the
// applier service has a different view of the cluster state from the one supplied here
final ClusterState appliedState = clusterService.state();
assert newState.stateUUID().equals(appliedState.stateUUID()) : newState.stateUUID() + " vs " + appliedState.stateUUID();
executeHealth(request, appliedState, listener, waitCount, observedState -> waitForEventsAndExecuteHealth(request, listener, waitCount, endTimeRelativeMillis));
}
@Override
public void onNoLongerMaster(String source) {
logger.trace("stopped being master while waiting for events with priority [{}]. retrying.", request.waitForEvents());
// TransportMasterNodeAction implements the retry logic, which is triggered by passing a NotMasterException
listener.onFailure(new NotMasterException("no longer master. source: [" + source + "]"));
}
@Override
public void onFailure(String source, Exception e) {
if (e instanceof ProcessClusterEventTimeoutException) {
listener.onResponse(getResponse(request, clusterService.state(), waitCount, TimeoutState.TIMED_OUT));
} else {
logger.error(() -> new ParameterizedMessage("unexpected failure during [{}]", source), e);
listener.onFailure(e);
}
}
});
}
}
Aggregations