/** * Note, this test can only work as long as we have a single thread executor executing the state * update tasks! */ @Test public void testPrioritizedTasks() throws Exception { Settings settings = settingsBuilder().put("discovery.type", "local").build(); internalCluster().startNode(settings); ClusterService clusterService = internalCluster().getInstance(ClusterService.class); BlockingTask block = new BlockingTask(); clusterService.submitStateUpdateTask("test", Priority.IMMEDIATE, block); int taskCount = randomIntBetween(5, 20); Priority[] priorities = Priority.values(); // will hold all the tasks in the order in which they were executed List<PrioritiezedTask> tasks = new ArrayList<>(taskCount); CountDownLatch latch = new CountDownLatch(taskCount); for (int i = 0; i < taskCount; i++) { Priority priority = priorities[randomIntBetween(0, priorities.length - 1)]; clusterService.submitStateUpdateTask( "test", priority, new PrioritiezedTask(priority, latch, tasks)); } block.release(); latch.await(); Priority prevPriority = null; for (PrioritiezedTask task : tasks) { if (prevPriority == null) { prevPriority = task.priority; } else { assertThat(task.priority.sameOrAfter(prevPriority), is(true)); } } }
@Test public void testTimeoutUpdateTask() throws Exception { Settings settings = settingsBuilder().put("discovery.type", "local").build(); internalCluster().startNode(settings); ClusterService clusterService1 = internalCluster().getInstance(ClusterService.class); final CountDownLatch block = new CountDownLatch(1); clusterService1.submitStateUpdateTask( "test1", new ClusterStateUpdateTask() { @Override public ClusterState execute(ClusterState currentState) { try { block.await(); } catch (InterruptedException e) { fail(); } return currentState; } @Override public void onFailure(String source, Throwable t) { fail(); } }); final CountDownLatch timedOut = new CountDownLatch(1); final AtomicBoolean executeCalled = new AtomicBoolean(); clusterService1.submitStateUpdateTask( "test2", new TimeoutClusterStateUpdateTask() { @Override public TimeValue timeout() { return TimeValue.timeValueMillis(2); } @Override public void onFailure(String source, Throwable t) { timedOut.countDown(); } @Override public ClusterState execute(ClusterState currentState) { executeCalled.set(true); return currentState; } @Override public void clusterStateProcessed( String source, ClusterState oldState, ClusterState newState) {} }); assertThat(timedOut.await(500, TimeUnit.MILLISECONDS), equalTo(true)); block.countDown(); Thread.sleep( 100); // sleep a bit to double check that execute on the timed out update task is not // called... assertThat(executeCalled.get(), equalTo(false)); }
@Test public void testMasterAwareExecution() throws Exception { Settings settings = settingsBuilder().put("discovery.type", "local").build(); ListenableFuture<String> master = internalCluster().startNodeAsync(settings); ListenableFuture<String> nonMaster = internalCluster() .startNodeAsync(settingsBuilder().put(settings).put("node.master", false).build()); master.get(); ensureGreen(); // make sure we have a cluster ClusterService clusterService = internalCluster().getInstance(ClusterService.class, nonMaster.get()); final boolean[] taskFailed = {false}; final CountDownLatch latch1 = new CountDownLatch(1); clusterService.submitStateUpdateTask( "test", new ClusterStateUpdateTask() { @Override public ClusterState execute(ClusterState currentState) throws Exception { latch1.countDown(); return currentState; } @Override public void onFailure(String source, Throwable t) { taskFailed[0] = true; latch1.countDown(); } }); latch1.await(); assertTrue("cluster state update task was executed on a non-master", taskFailed[0]); taskFailed[0] = true; final CountDownLatch latch2 = new CountDownLatch(1); clusterService.submitStateUpdateTask( "test", new ClusterStateNonMasterUpdateTask() { @Override public ClusterState execute(ClusterState currentState) throws Exception { taskFailed[0] = false; latch2.countDown(); return currentState; } @Override public void onFailure(String source, Throwable t) { taskFailed[0] = true; latch2.countDown(); } }); latch2.await(); assertFalse("non-master cluster state update task was not executed", taskFailed[0]); }
@Inject public MasterAwareService(Settings settings, ClusterService clusterService) { super(settings); clusterService.add(this); this.clusterService = clusterService; logger.info("initialized test service"); }
@Test @TestLogging("gateway:TRACE") public void testAssignmentWithJustAddedNodes() throws Exception { internalCluster().startNode(); final String index = "index"; prepareCreate(index) .setSettings( IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1, IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0) .get(); ensureGreen(index); // close to have some unassigned started shards shards.. client().admin().indices().prepareClose(index).get(); final String masterName = internalCluster().getMasterName(); final ClusterService clusterService = internalCluster().clusterService(masterName); final AllocationService allocationService = internalCluster().getInstance(AllocationService.class, masterName); clusterService.submitStateUpdateTask( "test-inject-node-and-reroute", new ClusterStateUpdateTask() { @Override public ClusterState execute(ClusterState currentState) throws Exception { // inject a node ClusterState.Builder builder = ClusterState.builder(currentState); builder.nodes( DiscoveryNodes.builder(currentState.nodes()) .put( new DiscoveryNode( "_non_existent", DummyTransportAddress.INSTANCE, Version.CURRENT))); // open index final IndexMetaData indexMetaData = IndexMetaData.builder(currentState.metaData().index(index)) .state(IndexMetaData.State.OPEN) .build(); builder.metaData(MetaData.builder(currentState.metaData()).put(indexMetaData, true)); builder.blocks( ClusterBlocks.builder().blocks(currentState.blocks()).removeIndexBlocks(index)); ClusterState updatedState = builder.build(); RoutingTable.Builder routingTable = RoutingTable.builder(updatedState.routingTable()); routingTable.addAsRecovery(updatedState.metaData().index(index)); updatedState = ClusterState.builder(updatedState).routingTable(routingTable).build(); RoutingAllocation.Result result = allocationService.reroute(updatedState); return ClusterState.builder(updatedState).routingResult(result).build(); } @Override public void onFailure(String source, Throwable t) {} }); ensureGreen(index); // remove the extra node clusterService.submitStateUpdateTask( "test-remove-injected-node", new ClusterStateUpdateTask() { @Override public ClusterState execute(ClusterState currentState) throws Exception { // inject a node ClusterState.Builder builder = ClusterState.builder(currentState); builder.nodes(DiscoveryNodes.builder(currentState.nodes()).remove("_non_existent")); currentState = builder.build(); RoutingAllocation.Result result = allocationService.reroute(currentState); return ClusterState.builder(currentState).routingResult(result).build(); } @Override public void onFailure(String source, Throwable t) {} }); }
@Override public void offMaster() { logger.info("off master [" + clusterService.localNode() + "]"); master = false; }
@Override public void onMaster() { logger.info("on master [" + clusterService.localNode() + "]"); master = true; }
@Test public void testLocalNodeMasterListenerCallbacks() throws Exception { Settings settings = settingsBuilder() .put("discovery.type", "zen") .put("discovery.zen.minimum_master_nodes", 1) .put("discovery.zen.ping_timeout", "400ms") .put("discovery.initial_state_timeout", "500ms") .put("plugin.types", TestPlugin.class.getName()) .build(); internalCluster().startNode(settings); ClusterService clusterService = internalCluster().getInstance(ClusterService.class); MasterAwareService testService = internalCluster().getInstance(MasterAwareService.class); ClusterHealthResponse clusterHealth = client() .admin() .cluster() .prepareHealth() .setWaitForEvents(Priority.LANGUID) .setWaitForNodes("1") .get(); assertThat(clusterHealth.isTimedOut(), equalTo(false)); // the first node should be a master as the minimum required is 1 assertThat(clusterService.state().nodes().masterNode(), notNullValue()); assertThat(clusterService.state().nodes().localNodeMaster(), is(true)); assertThat(testService.master(), is(true)); String node_1 = internalCluster().startNode(settings); final ClusterService clusterService1 = internalCluster().getInstance(ClusterService.class, node_1); MasterAwareService testService1 = internalCluster().getInstance(MasterAwareService.class, node_1); clusterHealth = client() .admin() .cluster() .prepareHealth() .setWaitForEvents(Priority.LANGUID) .setWaitForNodes("2") .get(); assertThat(clusterHealth.isTimedOut(), equalTo(false)); // the second node should not be the master as node1 is already the master. assertThat(clusterService1.state().nodes().localNodeMaster(), is(false)); assertThat(testService1.master(), is(false)); internalCluster().stopCurrentMasterNode(); clusterHealth = client() .admin() .cluster() .prepareHealth() .setWaitForEvents(Priority.LANGUID) .setWaitForNodes("1") .get(); assertThat(clusterHealth.isTimedOut(), equalTo(false)); // now that node1 is closed, node2 should be elected as master assertThat(clusterService1.state().nodes().localNodeMaster(), is(true)); assertThat(testService1.master(), is(true)); Settings transientSettings = settingsBuilder().put("discovery.zen.minimum_master_nodes", 2).build(); client() .admin() .cluster() .prepareUpdateSettings() .setTransientSettings(transientSettings) .get(); // there should not be any master as the minimum number of required eligible masters is not met awaitBusy( new Predicate<Object>() { public boolean apply(Object obj) { return clusterService1.state().nodes().masterNode() == null; } }); assertThat(testService1.master(), is(false)); String node_2 = internalCluster() .startNode(ImmutableSettings.builder().put(settings).put(transientSettings)); ClusterService clusterService2 = internalCluster().getInstance(ClusterService.class, node_2); MasterAwareService testService2 = internalCluster().getInstance(MasterAwareService.class, node_2); // make sure both nodes see each other otherwise the masternode below could be null if node 2 is // master and node 1 did'r receive the updated cluster state... assertThat( internalCluster() .client(node_1) .admin() .cluster() .prepareHealth() .setWaitForEvents(Priority.LANGUID) .setLocal(true) .setWaitForNodes("2") .get() .isTimedOut(), is(false)); assertThat( internalCluster() .client(node_2) .admin() .cluster() .prepareHealth() .setWaitForEvents(Priority.LANGUID) .setLocal(true) .setWaitForNodes("2") .get() .isTimedOut(), is(false)); // now that we started node1 again, a new master should be elected assertThat(clusterService2.state().nodes().masterNode(), is(notNullValue())); if (node_2.equals(clusterService2.state().nodes().masterNode().name())) { assertThat(testService1.master(), is(false)); assertThat(testService2.master(), is(true)); } else { assertThat(testService1.master(), is(true)); assertThat(testService2.master(), is(false)); } }
@Test public void testPendingUpdateTask() throws Exception { Settings settings = settingsBuilder().put("discovery.type", "local").build(); String node_0 = internalCluster().startNode(settings); internalCluster().startNodeClient(settings); final ClusterService clusterService = internalCluster().getInstance(ClusterService.class, node_0); final CountDownLatch block1 = new CountDownLatch(1); final CountDownLatch invoked1 = new CountDownLatch(1); clusterService.submitStateUpdateTask( "1", new ClusterStateUpdateTask() { @Override public ClusterState execute(ClusterState currentState) { invoked1.countDown(); try { block1.await(); } catch (InterruptedException e) { fail(); } return currentState; } @Override public void onFailure(String source, Throwable t) { invoked1.countDown(); fail(); } }); invoked1.await(); final CountDownLatch invoked2 = new CountDownLatch(9); for (int i = 2; i <= 10; i++) { clusterService.submitStateUpdateTask( Integer.toString(i), new ProcessedClusterStateUpdateTask() { @Override public ClusterState execute(ClusterState currentState) { return currentState; } @Override public void onFailure(String source, Throwable t) { fail(); } @Override public void clusterStateProcessed( String source, ClusterState oldState, ClusterState newState) { invoked2.countDown(); } }); } // there might be other tasks in this node, make sure to only take the ones we add into account // in this test // The tasks can be re-ordered, so we need to check out-of-order Set<String> controlSources = new HashSet<>(Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10")); List<PendingClusterTask> pendingClusterTasks = clusterService.pendingTasks(); assertThat(pendingClusterTasks.size(), greaterThanOrEqualTo(10)); assertThat(pendingClusterTasks.get(0).getSource().string(), equalTo("1")); assertThat(pendingClusterTasks.get(0).isExecuting(), equalTo(true)); for (PendingClusterTask task : pendingClusterTasks) { controlSources.remove(task.getSource().string()); } assertTrue(controlSources.isEmpty()); controlSources = new HashSet<>(Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10")); PendingClusterTasksResponse response = internalCluster() .clientNodeClient() .admin() .cluster() .preparePendingClusterTasks() .execute() .actionGet(); assertThat(response.pendingTasks().size(), greaterThanOrEqualTo(10)); assertThat(response.pendingTasks().get(0).getSource().string(), equalTo("1")); assertThat(response.pendingTasks().get(0).isExecuting(), equalTo(true)); for (PendingClusterTask task : response) { controlSources.remove(task.getSource().string()); } assertTrue(controlSources.isEmpty()); block1.countDown(); invoked2.await(); // whenever we test for no tasks, we need to awaitBusy since this is a live node assertTrue( awaitBusy( new Predicate<Object>() { @Override public boolean apply(Object input) { return clusterService.pendingTasks().isEmpty(); } })); waitNoPendingTasksOnAll(); final CountDownLatch block2 = new CountDownLatch(1); final CountDownLatch invoked3 = new CountDownLatch(1); clusterService.submitStateUpdateTask( "1", new ClusterStateUpdateTask() { @Override public ClusterState execute(ClusterState currentState) { invoked3.countDown(); try { block2.await(); } catch (InterruptedException e) { fail(); } return currentState; } @Override public void onFailure(String source, Throwable t) { invoked3.countDown(); fail(); } }); invoked3.await(); for (int i = 2; i <= 5; i++) { clusterService.submitStateUpdateTask( Integer.toString(i), new ClusterStateUpdateTask() { @Override public ClusterState execute(ClusterState currentState) { return currentState; } @Override public void onFailure(String source, Throwable t) { fail(); } }); } Thread.sleep(100); pendingClusterTasks = clusterService.pendingTasks(); assertThat(pendingClusterTasks.size(), greaterThanOrEqualTo(5)); controlSources = new HashSet<>(Arrays.asList("1", "2", "3", "4", "5")); for (PendingClusterTask task : pendingClusterTasks) { controlSources.remove(task.getSource().string()); } assertTrue(controlSources.isEmpty()); response = internalCluster().clientNodeClient().admin().cluster().preparePendingClusterTasks().get(); assertThat(response.pendingTasks().size(), greaterThanOrEqualTo(5)); controlSources = new HashSet<>(Arrays.asList("1", "2", "3", "4", "5")); for (PendingClusterTask task : response) { if (controlSources.remove(task.getSource().string())) { assertThat(task.getTimeInQueueInMillis(), greaterThan(0l)); } } assertTrue(controlSources.isEmpty()); block2.countDown(); }
@Test public void testAckedUpdateTaskTimeoutZero() throws Exception { Settings settings = settingsBuilder().put("discovery.type", "local").build(); internalCluster().startNode(settings); ClusterService clusterService = internalCluster().getInstance(ClusterService.class); final AtomicBoolean allNodesAcked = new AtomicBoolean(false); final AtomicBoolean ackTimeout = new AtomicBoolean(false); final AtomicBoolean onFailure = new AtomicBoolean(false); final AtomicBoolean executed = new AtomicBoolean(false); final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch processedLatch = new CountDownLatch(1); clusterService.submitStateUpdateTask( "test", new AckedClusterStateUpdateTask<Void>(null, null) { @Override protected Void newResponse(boolean acknowledged) { return null; } @Override public boolean mustAck(DiscoveryNode discoveryNode) { return false; } @Override public void onAllNodesAcked(@Nullable Throwable t) { allNodesAcked.set(true); latch.countDown(); } @Override public void onAckTimeout() { ackTimeout.set(true); latch.countDown(); } @Override public TimeValue ackTimeout() { return TimeValue.timeValueSeconds(0); } @Override public TimeValue timeout() { return TimeValue.timeValueSeconds(10); } @Override public void clusterStateProcessed( String source, ClusterState oldState, ClusterState newState) { processedLatch.countDown(); } @Override public ClusterState execute(ClusterState currentState) throws Exception { executed.set(true); return ClusterState.builder(currentState).build(); } @Override public void onFailure(String source, Throwable t) { logger.error("failed to execute callback in test {}", t, source); onFailure.set(true); latch.countDown(); } }); assertThat(latch.await(1, TimeUnit.SECONDS), equalTo(true)); assertThat(allNodesAcked.get(), equalTo(false)); assertThat(ackTimeout.get(), equalTo(true)); assertThat(executed.get(), equalTo(true)); assertThat(onFailure.get(), equalTo(false)); assertThat(processedLatch.await(1, TimeUnit.SECONDS), equalTo(true)); }