/**
  * For a fixed thread pool the task is queued to a thread waiting on I/O events. For other thread
  * pools we simply submit the task to the thread pool.
  */
 final void executeOnPooledThread(Runnable task) {
   if (isFixedThreadPool()) {
     executeOnHandlerTask(task);
   } else {
     pool.executor().execute(bindToGroup(task));
   }
 }
 /** Invoked by tasks as they terminate */
 final int threadExit(Runnable task, boolean replaceMe) {
   if (replaceMe) {
     try {
       if (Invoker.isBoundToAnyGroup()) {
         // submit new task to replace this thread
         pool.executor().execute(bindToGroup(task));
       } else {
         // replace internal thread
         startInternalThread(task);
       }
       return threadCount.get();
     } catch (RejectedExecutionException x) {
       // unable to replace
     }
   }
   return threadCount.decrementAndGet();
 }
 protected final void startThreads(Runnable task) {
   if (!isFixedThreadPool()) {
     for (int i = 0; i < internalThreadCount; i++) {
       startInternalThread(task);
       threadCount.incrementAndGet();
     }
   }
   if (pool.poolSize() > 0) {
     task = bindToGroup(task);
     try {
       for (int i = 0; i < pool.poolSize(); i++) {
         pool.executor().execute(task);
         threadCount.incrementAndGet();
       }
     } catch (RejectedExecutionException x) {
       // nothing we can do
     }
   }
 }
 final ExecutorService executor() {
   return pool.executor();
 }
 @Override
 public final boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
   return pool.executor().awaitTermination(timeout, unit);
 }
 @Override
 public final boolean isTerminated() {
   return pool.executor().isTerminated();
 }
  @Test(timeout = 20000)
  public void testUpdatingThreadPoolSettings() throws Exception {
    internalCluster().startNodesAsync(2).get();
    ThreadPool threadPool = internalCluster().getDataNodeInstance(ThreadPool.class);
    // Check that settings are changed
    assertThat(
        ((ThreadPoolExecutor) threadPool.executor(Names.SEARCH)).getKeepAliveTime(TimeUnit.MINUTES),
        equalTo(5L));
    client()
        .admin()
        .cluster()
        .prepareUpdateSettings()
        .setTransientSettings(settingsBuilder().put("threadpool.search.keep_alive", "10m").build())
        .execute()
        .actionGet();
    assertThat(
        ((ThreadPoolExecutor) threadPool.executor(Names.SEARCH)).getKeepAliveTime(TimeUnit.MINUTES),
        equalTo(10L));

    // Make sure that threads continue executing when executor is replaced
    final CyclicBarrier barrier = new CyclicBarrier(2);
    Executor oldExecutor = threadPool.executor(Names.SEARCH);
    threadPool
        .executor(Names.SEARCH)
        .execute(
            new Runnable() {
              @Override
              public void run() {
                try {
                  barrier.await();
                } catch (InterruptedException ex) {
                  Thread.currentThread().interrupt();
                } catch (BrokenBarrierException ex) {
                  //
                }
              }
            });
    client()
        .admin()
        .cluster()
        .prepareUpdateSettings()
        .setTransientSettings(settingsBuilder().put("threadpool.search.type", "fixed").build())
        .execute()
        .actionGet();
    assertThat(threadPool.executor(Names.SEARCH), not(sameInstance(oldExecutor)));
    assertThat(((ThreadPoolExecutor) oldExecutor).isShutdown(), equalTo(true));
    assertThat(((ThreadPoolExecutor) oldExecutor).isTerminating(), equalTo(true));
    assertThat(((ThreadPoolExecutor) oldExecutor).isTerminated(), equalTo(false));
    barrier.await();

    // Make sure that new thread executor is functional
    threadPool
        .executor(Names.SEARCH)
        .execute(
            new Runnable() {
              @Override
              public void run() {
                try {
                  barrier.await();
                } catch (InterruptedException ex) {
                  Thread.currentThread().interrupt();
                } catch (BrokenBarrierException ex) {
                  //
                }
              }
            });
    client()
        .admin()
        .cluster()
        .prepareUpdateSettings()
        .setTransientSettings(settingsBuilder().put("threadpool.search.type", "fixed").build())
        .execute()
        .actionGet();
    barrier.await();
    Thread.sleep(200);

    // Check that node info is correct
    NodesInfoResponse nodesInfoResponse =
        client().admin().cluster().prepareNodesInfo().all().execute().actionGet();
    for (int i = 0; i < 2; i++) {
      NodeInfo nodeInfo = nodesInfoResponse.getNodes()[i];
      boolean found = false;
      for (ThreadPool.Info info : nodeInfo.getThreadPool()) {
        if (info.getName().equals(Names.SEARCH)) {
          assertThat(info.getType(), equalTo("fixed"));
          found = true;
          break;
        }
      }
      assertThat(found, equalTo(true));

      Map<String, Object> poolMap =
          getPoolSettingsThroughJson(nodeInfo.getThreadPool(), Names.SEARCH);
    }
  }