This is an automated email from the ASF dual-hosted git repository.
kfaraz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new 093d60a0489 Remove usages of DruidLeaderClient from extensions (#18297)
093d60a0489 is described below
commit 093d60a04892b2181bc830caff7d3dca773c3357
Author: Kashif Faraz <[email protected]>
AuthorDate: Wed Jul 23 17:02:06 2025 +0530
Remove usages of DruidLeaderClient from extensions (#18297)
Description:
This is a follow up to the work done by @uds5501 in #18142 , #18192 and
#18195
to replace usages of `DruidLeaderClient` with a `ServiceClient`-based
implementation.
Changes:
- Remove usages of `DruidLeaderClient` in extensions `druid-basic-security`
and `druid-catalog`
- Use `ServiceClient` to make HTTP calls instead
- Remove classes `DruidLeaderClient`, `CoordinatorDiscoveryModule`
- Add embedded test `CatalogCompactionTest`
---
embedded-tests/pom.xml | 6 +
.../security/basic/BasicSecurityDruidModule.java | 15 +
.../security/basic/CoordinatorServiceClient.java | 52 ++++
...natorPollingBasicAuthenticatorCacheManager.java | 15 +-
...rdinatorPollingBasicAuthorizerCacheManager.java | 19 +-
...rPollingBasicAuthenticatorCacheManagerTest.java | 68 +++--
...atorPollingBasicAuthorizerCacheManagerTest.java | 116 ++++---
extensions-core/druid-catalog/pom.xml | 23 ++
.../apache/druid/catalog/sync/CatalogClient.java | 175 +++++++----
.../catalog/compact/CatalogCompactionTest.java | 163 ++++++++++
...posedAsBrokerQueryComponentSupplierWrapper.java | 2 -
.../apache/druid/discovery/DruidLeaderClient.java | 307 -------------------
.../druid/guice/CoordinatorDiscoveryModule.java | 58 ----
.../druid/initialization/CoreInjectorBuilder.java | 2 -
.../query/lookup/LookupReferencesManager.java | 24 +-
.../druid/server/http/ServletResourceUtils.java | 23 ++
.../druid/discovery/DruidLeaderClientTest.java | 338 ---------------------
.../server/http/ServletResourceUtilsTest.java | 40 +++
.../testing/embedded/ServerReferenceHolder.java | 10 +
.../testing/embedded/ServerReferencesProvider.java | 6 +
.../druid/testing/embedded/indexing/Resources.java | 0
.../druid/sql/calcite/schema/SystemSchema.java | 55 ----
.../schema/DruidCalciteSchemaModuleTest.java | 13 -
.../org/apache/druid/sql/guice/SqlModuleTest.java | 9 -
24 files changed, 578 insertions(+), 961 deletions(-)
diff --git a/embedded-tests/pom.xml b/embedded-tests/pom.xml
index 1392f15c806..fc36eee0eb5 100644
--- a/embedded-tests/pom.xml
+++ b/embedded-tests/pom.xml
@@ -153,6 +153,12 @@
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.druid.extensions</groupId>
+ <artifactId>druid-catalog</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
<!-- Some embedded tests use the router and the web-console for debugging
-->
<dependency>
<groupId>org.apache.druid</groupId>
diff --git
a/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/BasicSecurityDruidModule.java
b/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/BasicSecurityDruidModule.java
index fceaf7f2202..fa4d39d6c5c 100644
---
a/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/BasicSecurityDruidModule.java
+++
b/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/BasicSecurityDruidModule.java
@@ -27,12 +27,16 @@ import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provides;
import com.google.inject.name.Names;
+import org.apache.druid.client.coordinator.Coordinator;
import org.apache.druid.guice.Jerseys;
import org.apache.druid.guice.JsonConfigProvider;
import org.apache.druid.guice.LazySingleton;
import org.apache.druid.guice.LifecycleModule;
+import org.apache.druid.guice.annotations.EscalatedGlobal;
import org.apache.druid.initialization.DruidModule;
import org.apache.druid.java.util.http.client.NettyHttpClient;
+import org.apache.druid.rpc.ServiceClientFactory;
+import org.apache.druid.rpc.ServiceLocator;
import org.apache.druid.security.basic.authentication.BasicHTTPAuthenticator;
import org.apache.druid.security.basic.authentication.BasicHTTPEscalator;
import
org.apache.druid.security.basic.authentication.db.cache.BasicAuthenticatorCacheManager;
@@ -207,6 +211,17 @@ public class BasicSecurityDruidModule implements
DruidModule
NoopBasicAuthorizerCacheNotifier.class
);
}
+
+ @Provides
+ @LazySingleton
+ public static CoordinatorServiceClient createCoordinatorServiceClient(
+ @EscalatedGlobal ServiceClientFactory clientFactory,
+ @Coordinator ServiceLocator serviceLocator,
+ BasicAuthCommonCacheConfig cacheConfig
+ )
+ {
+ return new CoordinatorServiceClient(clientFactory, serviceLocator,
cacheConfig);
+ }
@Override
public List<? extends Module> getJacksonModules()
diff --git
a/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/CoordinatorServiceClient.java
b/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/CoordinatorServiceClient.java
new file mode 100644
index 00000000000..171bfe5d2c5
--- /dev/null
+++
b/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/CoordinatorServiceClient.java
@@ -0,0 +1,52 @@
+/*
+ * 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.druid.security.basic;
+
+import org.apache.druid.discovery.NodeRole;
+import org.apache.druid.rpc.ServiceClient;
+import org.apache.druid.rpc.ServiceClientFactory;
+import org.apache.druid.rpc.ServiceLocator;
+import org.apache.druid.rpc.StandardRetryPolicy;
+
+/**
+ * Wrapper over {@link ServiceClient} used to query the Coordinator.
+ */
+public class CoordinatorServiceClient
+{
+ private final ServiceClient serviceClient;
+
+ public CoordinatorServiceClient(
+ ServiceClientFactory clientFactory,
+ ServiceLocator coordinatorServiceLocator,
+ BasicAuthCommonCacheConfig cacheConfig
+ )
+ {
+ this.serviceClient = clientFactory.makeClient(
+ NodeRole.COORDINATOR.getJsonName(),
+ coordinatorServiceLocator,
+
StandardRetryPolicy.builder().maxAttempts(cacheConfig.getMaxSyncRetries()).build()
+ );
+ }
+
+ public ServiceClient getServiceClient()
+ {
+ return serviceClient;
+ }
+}
diff --git
a/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authentication/db/cache/CoordinatorPollingBasicAuthenticatorCacheManager.java
b/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authentication/db/cache/CoordinatorPollingBasicAuthenticatorCacheManager.java
index 51758b9ec6e..3be5ca5b936 100644
---
a/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authentication/db/cache/CoordinatorPollingBasicAuthenticatorCacheManager.java
+++
b/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authentication/db/cache/CoordinatorPollingBasicAuthenticatorCacheManager.java
@@ -24,9 +24,7 @@ import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.Injector;
import org.apache.commons.lang3.ArrayUtils;
-import org.apache.druid.client.coordinator.Coordinator;
import org.apache.druid.concurrent.LifecycleLock;
-import org.apache.druid.discovery.DruidLeaderClient;
import org.apache.druid.guice.ManageLifecycle;
import org.apache.druid.guice.annotations.Smile;
import org.apache.druid.java.util.common.FileUtils;
@@ -38,11 +36,12 @@ import
org.apache.druid.java.util.common.concurrent.ScheduledExecutors;
import org.apache.druid.java.util.common.lifecycle.LifecycleStart;
import org.apache.druid.java.util.common.lifecycle.LifecycleStop;
import org.apache.druid.java.util.emitter.EmittingLogger;
-import org.apache.druid.java.util.http.client.Request;
import
org.apache.druid.java.util.http.client.response.BytesFullResponseHandler;
import org.apache.druid.java.util.http.client.response.BytesFullResponseHolder;
+import org.apache.druid.rpc.RequestBuilder;
import org.apache.druid.security.basic.BasicAuthCommonCacheConfig;
import org.apache.druid.security.basic.BasicAuthUtils;
+import org.apache.druid.security.basic.CoordinatorServiceClient;
import org.apache.druid.security.basic.authentication.BasicHTTPAuthenticator;
import
org.apache.druid.security.basic.authentication.entity.BasicAuthenticatorUser;
import org.apache.druid.server.security.Authenticator;
@@ -74,7 +73,7 @@ public class CoordinatorPollingBasicAuthenticatorCacheManager
implements BasicAu
private final Injector injector;
private final ObjectMapper objectMapper;
private final LifecycleLock lifecycleLock = new LifecycleLock();
- private final DruidLeaderClient druidLeaderClient;
+ private final CoordinatorServiceClient coordinatorClient;
private final BasicAuthCommonCacheConfig commonCacheConfig;
private final ScheduledExecutorService exec;
@@ -83,7 +82,7 @@ public class CoordinatorPollingBasicAuthenticatorCacheManager
implements BasicAu
Injector injector,
BasicAuthCommonCacheConfig commonCacheConfig,
@Smile ObjectMapper objectMapper,
- @Coordinator DruidLeaderClient druidLeaderClient
+ CoordinatorServiceClient coordinatorClient
)
{
this.exec =
Execs.scheduledSingleThreaded("BasicAuthenticatorCacheManager-Exec--%d");
@@ -92,7 +91,7 @@ public class CoordinatorPollingBasicAuthenticatorCacheManager
implements BasicAu
this.objectMapper = objectMapper;
this.cachedUserMaps = new ConcurrentHashMap<>();
this.authenticatorPrefixes = new HashSet<>();
- this.druidLeaderClient = druidLeaderClient;
+ this.coordinatorClient = coordinatorClient;
}
@LifecycleStart
@@ -254,11 +253,11 @@ public class
CoordinatorPollingBasicAuthenticatorCacheManager implements BasicAu
private Map<String, BasicAuthenticatorUser>
tryFetchUserMapFromCoordinator(String prefix) throws Exception
{
Map<String, BasicAuthenticatorUser> userMap = null;
- Request req = druidLeaderClient.makeRequest(
+ RequestBuilder req = new RequestBuilder(
HttpMethod.GET,
StringUtils.format("/druid-ext/basic-security/authentication/db/%s/cachedSerializedUserMap",
prefix)
);
- BytesFullResponseHolder responseHolder = druidLeaderClient.go(
+ BytesFullResponseHolder responseHolder =
coordinatorClient.getServiceClient().request(
req,
new BytesFullResponseHandler()
);
diff --git
a/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/db/cache/CoordinatorPollingBasicAuthorizerCacheManager.java
b/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/db/cache/CoordinatorPollingBasicAuthorizerCacheManager.java
index 4bebc38b210..ee53f6e9c3e 100644
---
a/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/db/cache/CoordinatorPollingBasicAuthorizerCacheManager.java
+++
b/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/db/cache/CoordinatorPollingBasicAuthorizerCacheManager.java
@@ -23,9 +23,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.Injector;
-import org.apache.druid.client.coordinator.Coordinator;
import org.apache.druid.concurrent.LifecycleLock;
-import org.apache.druid.discovery.DruidLeaderClient;
import org.apache.druid.guice.ManageLifecycle;
import org.apache.druid.guice.annotations.Smile;
import org.apache.druid.java.util.common.FileUtils;
@@ -37,11 +35,12 @@ import
org.apache.druid.java.util.common.concurrent.ScheduledExecutors;
import org.apache.druid.java.util.common.lifecycle.LifecycleStart;
import org.apache.druid.java.util.common.lifecycle.LifecycleStop;
import org.apache.druid.java.util.emitter.EmittingLogger;
-import org.apache.druid.java.util.http.client.Request;
import
org.apache.druid.java.util.http.client.response.BytesFullResponseHandler;
import org.apache.druid.java.util.http.client.response.BytesFullResponseHolder;
+import org.apache.druid.rpc.RequestBuilder;
import org.apache.druid.security.basic.BasicAuthCommonCacheConfig;
import org.apache.druid.security.basic.BasicAuthUtils;
+import org.apache.druid.security.basic.CoordinatorServiceClient;
import org.apache.druid.security.basic.authorization.BasicRoleBasedAuthorizer;
import
org.apache.druid.security.basic.authorization.entity.BasicAuthorizerGroupMapping;
import
org.apache.druid.security.basic.authorization.entity.BasicAuthorizerRole;
@@ -79,7 +78,7 @@ public class CoordinatorPollingBasicAuthorizerCacheManager
implements BasicAutho
private final Injector injector;
private final ObjectMapper objectMapper;
private final LifecycleLock lifecycleLock = new LifecycleLock();
- private final DruidLeaderClient druidLeaderClient;
+ private final CoordinatorServiceClient coordinatorClient;
private final BasicAuthCommonCacheConfig commonCacheConfig;
private final ScheduledExecutorService exec;
@@ -88,7 +87,7 @@ public class CoordinatorPollingBasicAuthorizerCacheManager
implements BasicAutho
Injector injector,
BasicAuthCommonCacheConfig commonCacheConfig,
@Smile ObjectMapper objectMapper,
- @Coordinator DruidLeaderClient druidLeaderClient
+ CoordinatorServiceClient coordinatorClient
)
{
this.exec =
Execs.scheduledSingleThreaded("CoordinatorPollingBasicAuthorizerCacheManager-Exec--%d");
@@ -100,7 +99,7 @@ public class CoordinatorPollingBasicAuthorizerCacheManager
implements BasicAutho
this.cachedGroupMappingMaps = new ConcurrentHashMap<>();
this.cachedGroupMappingRoleMaps = new ConcurrentHashMap<>();
this.authorizerPrefixes = new HashSet<>();
- this.druidLeaderClient = druidLeaderClient;
+ this.coordinatorClient = coordinatorClient;
}
@LifecycleStart
@@ -397,11 +396,11 @@ public class
CoordinatorPollingBasicAuthorizerCacheManager implements BasicAutho
String prefix
) throws Exception
{
- Request req = druidLeaderClient.makeRequest(
+ RequestBuilder req = new RequestBuilder(
HttpMethod.GET,
StringUtils.format("/druid-ext/basic-security/authorization/db/%s/cachedSerializedUserMap",
prefix)
);
- BytesFullResponseHolder responseHolder = druidLeaderClient.go(
+ BytesFullResponseHolder responseHolder =
coordinatorClient.getServiceClient().request(
req,
new BytesFullResponseHandler()
);
@@ -421,11 +420,11 @@ public class
CoordinatorPollingBasicAuthorizerCacheManager implements BasicAutho
String prefix
) throws Exception
{
- Request req = druidLeaderClient.makeRequest(
+ RequestBuilder req = new RequestBuilder(
HttpMethod.GET,
StringUtils.format("/druid-ext/basic-security/authorization/db/%s/cachedSerializedGroupMappingMap",
prefix)
);
- BytesFullResponseHolder responseHolder = druidLeaderClient.go(
+ BytesFullResponseHolder responseHolder =
coordinatorClient.getServiceClient().request(
req,
new BytesFullResponseHandler()
);
diff --git
a/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/basic/authentication/db/cache/CoordinatorPollingBasicAuthenticatorCacheManagerTest.java
b/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/basic/authentication/db/cache/CoordinatorPollingBasicAuthenticatorCacheManagerTest.java
index f06d2deeb04..af041ad5a35 100644
---
a/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/basic/authentication/db/cache/CoordinatorPollingBasicAuthenticatorCacheManagerTest.java
+++
b/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/basic/authentication/db/cache/CoordinatorPollingBasicAuthenticatorCacheManagerTest.java
@@ -20,22 +20,29 @@
package org.apache.druid.security.basic.authentication.db.cache;
import com.google.inject.Injector;
-import org.apache.druid.discovery.DruidLeaderClient;
+import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.java.util.emitter.EmittingLogger;
-import org.apache.druid.java.util.http.client.Request;
-import
org.apache.druid.java.util.http.client.response.BytesFullResponseHandler;
-import org.apache.druid.java.util.http.client.response.BytesFullResponseHolder;
import org.apache.druid.java.util.metrics.StubServiceEmitter;
+import org.apache.druid.rpc.MockServiceClient;
+import org.apache.druid.rpc.RequestBuilder;
import org.apache.druid.security.basic.BasicAuthCommonCacheConfig;
+import org.apache.druid.security.basic.CoordinatorServiceClient;
import org.apache.druid.security.basic.authentication.BasicHTTPAuthenticator;
import org.apache.druid.segment.TestHelper;
import org.apache.druid.server.security.AuthenticatorMapper;
import org.easymock.EasyMock;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
+import org.jboss.netty.handler.codec.http.HttpMethod;
+import org.jboss.netty.handler.codec.http.HttpResponseStatus;
+import org.jboss.netty.handler.codec.http.HttpVersion;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -56,35 +63,42 @@ public class
CoordinatorPollingBasicAuthenticatorCacheManagerTest
.andReturn(new AuthenticatorMapper(Map.of("test-basic-auth",
authenticator))).once();
// Create a mock leader client and request
- final DruidLeaderClient leaderClient =
EasyMock.createStrictMock(DruidLeaderClient.class);
- final Request request = EasyMock.createStrictMock(Request.class);
+ final CoordinatorServiceClient leaderClient =
EasyMock.createStrictMock(CoordinatorServiceClient.class);
+ final MockServiceClient serviceClient = new MockServiceClient();
+
EasyMock.expect(leaderClient.getServiceClient()).andReturn(serviceClient).anyTimes();
// Return the first request immediately
- EasyMock.expect(leaderClient.makeRequest(EasyMock.anyObject(),
EasyMock.anyString()))
- .andReturn(request).once();
- EasyMock.expect(
- leaderClient.go(EasyMock.anyObject(),
EasyMock.anyObject(BytesFullResponseHandler.class))
- ).andReturn(
- new BytesFullResponseHolder(null)
- ).once();
+ final String path = StringUtils.format(
+
"/druid-ext/basic-security/authentication/db/%s/cachedSerializedUserMap",
+ "test-basic-auth"
+ );
+ serviceClient.expectAndRespond(
+ new RequestBuilder(HttpMethod.GET, path),
+ HttpResponseStatus.OK,
+ Map.of(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON),
+ new byte[0]
+ );
// Block the second request so that it can be interrupted by stop()
final AtomicBoolean isInterrupted = new AtomicBoolean(false);
- EasyMock.expect(leaderClient.makeRequest(EasyMock.anyObject(),
EasyMock.anyString()))
- .andReturn(request).once();
- EasyMock.expect(
- leaderClient.go(EasyMock.anyObject(),
EasyMock.anyObject(BytesFullResponseHandler.class))
- ).andAnswer(() -> {
- try {
- Thread.sleep(10_000);
- return null;
- }
- catch (InterruptedException e) {
- isInterrupted.set(true);
- throw e;
- }
- }).once();
+ serviceClient.expectAndRespond(
+ new RequestBuilder(HttpMethod.GET, path),
+ new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK) {
+ @Override
+ public ChannelBuffer getContent()
+ {
+ try {
+ Thread.sleep(10_000);
+ return null;
+ }
+ catch (InterruptedException e) {
+ isInterrupted.set(true);
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ );
EasyMock.replay(injector, leaderClient);
diff --git
a/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/basic/authorization/db/cache/CoordinatorPollingBasicAuthorizerCacheManagerTest.java
b/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/basic/authorization/db/cache/CoordinatorPollingBasicAuthorizerCacheManagerTest.java
index 602f90e4461..115132330e2 100644
---
a/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/basic/authorization/db/cache/CoordinatorPollingBasicAuthorizerCacheManagerTest.java
+++
b/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/basic/authorization/db/cache/CoordinatorPollingBasicAuthorizerCacheManagerTest.java
@@ -21,14 +21,15 @@ package
org.apache.druid.security.basic.authorization.db.cache;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.inject.Injector;
-import org.apache.druid.discovery.DruidLeaderClient;
+import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.java.util.common.jackson.JacksonUtils;
import org.apache.druid.java.util.emitter.EmittingLogger;
-import org.apache.druid.java.util.http.client.Request;
-import
org.apache.druid.java.util.http.client.response.BytesFullResponseHandler;
import org.apache.druid.java.util.http.client.response.BytesFullResponseHolder;
import org.apache.druid.java.util.metrics.StubServiceEmitter;
+import org.apache.druid.rpc.MockServiceClient;
+import org.apache.druid.rpc.RequestBuilder;
import org.apache.druid.security.basic.BasicAuthCommonCacheConfig;
+import org.apache.druid.security.basic.CoordinatorServiceClient;
import org.apache.druid.security.basic.authorization.BasicRoleBasedAuthorizer;
import
org.apache.druid.security.basic.authorization.entity.GroupMappingAndRoleMap;
import org.apache.druid.security.basic.authorization.entity.UserAndRoleMap;
@@ -36,7 +37,10 @@ import org.apache.druid.segment.TestHelper;
import org.apache.druid.server.security.AuthorizerMapper;
import org.easymock.EasyMock;
import org.easymock.IAnswer;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
+import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.jboss.netty.handler.codec.http.HttpVersion;
@@ -53,14 +57,15 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class CoordinatorPollingBasicAuthorizerCacheManagerTest
{
private static final ObjectMapper MAPPER = TestHelper.JSON_MAPPER;
+ private static final String AUTHORIZER_NAME = "test-basic-auth";
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
// Mocks
- private Request request;
private Injector injector;
- private DruidLeaderClient leaderClient;
+ private CoordinatorServiceClient leaderClient;
+ private MockServiceClient serviceClient;
private CoordinatorPollingBasicAuthorizerCacheManager manager;
@@ -72,12 +77,13 @@ public class
CoordinatorPollingBasicAuthorizerCacheManagerTest
final BasicRoleBasedAuthorizer authorizer =
EasyMock.createStrictMock(BasicRoleBasedAuthorizer.class);
injector = EasyMock.createStrictMock(Injector.class);
EasyMock.expect(injector.getInstance(AuthorizerMapper.class))
- .andReturn(new AuthorizerMapper(Map.of("test-basic-auth",
authorizer))).once();
+ .andReturn(new AuthorizerMapper(Map.of(AUTHORIZER_NAME,
authorizer))).once();
- request = EasyMock.createStrictMock(Request.class);
- leaderClient = EasyMock.createStrictMock(DruidLeaderClient.class);
+ serviceClient = new MockServiceClient();
+ leaderClient = EasyMock.createStrictMock(CoordinatorServiceClient.class);
+
EasyMock.expect(leaderClient.getServiceClient()).andReturn(serviceClient).anyTimes();
- final int numRetries = 10;
+ final int numRetries = 1;
manager = new CoordinatorPollingBasicAuthorizerCacheManager(
injector,
new BasicAuthCommonCacheConfig(0L, 1L,
temporaryFolder.newFolder().getAbsolutePath(), numRetries),
@@ -107,21 +113,24 @@ public class
CoordinatorPollingBasicAuthorizerCacheManagerTest
groupResponseHolder.addChunk(JacksonUtils.toBytes(MAPPER, new
GroupMappingAndRoleMap(Map.of(), Map.of())));
// Return the first set of requests immediately
- expectHttpRequestAndAnswer(() -> userResponseHolder);
- expectHttpRequestAndAnswer(() -> groupResponseHolder);
+ expectHttpRequestAndAnswer("cachedSerializedUserMap", () ->
userResponseHolder);
+ expectHttpRequestAndAnswer("cachedSerializedGroupMappingMap", () ->
groupResponseHolder);
// Block the second user request so that it can be interrupted by stop()
final AtomicBoolean isInterrupted = new AtomicBoolean(false);
- expectHttpRequestAndAnswer(() -> {
- try {
- Thread.sleep(10_000);
- return userResponseHolder;
- }
- catch (InterruptedException e) {
- isInterrupted.set(true);
- throw e;
- }
- });
+ expectHttpRequestAndAnswer(
+ "cachedSerializedUserMap",
+ () -> {
+ try {
+ Thread.sleep(10_000);
+ return userResponseHolder;
+ }
+ catch (InterruptedException e) {
+ isInterrupted.set(true);
+ throw e;
+ }
+ }
+ );
replayAll();
@@ -149,24 +158,27 @@ public class
CoordinatorPollingBasicAuthorizerCacheManagerTest
groupResponseHolder.addChunk(JacksonUtils.toBytes(MAPPER, new
GroupMappingAndRoleMap(Map.of(), Map.of())));
// Return the first set of requests immediately
- expectHttpRequestAndAnswer(() -> userResponseHolder);
- expectHttpRequestAndAnswer(() -> groupResponseHolder);
+ expectHttpRequestAndAnswer("cachedSerializedUserMap", () ->
userResponseHolder);
+ expectHttpRequestAndAnswer("cachedSerializedGroupMappingMap", () ->
groupResponseHolder);
// Return the second user request immediately
- expectHttpRequestAndAnswer(() -> userResponseHolder);
+ expectHttpRequestAndAnswer("cachedSerializedUserMap", () ->
userResponseHolder);
// Block the second group request so that it can be interrupted by stop()
final AtomicBoolean isInterrupted = new AtomicBoolean(false);
- expectHttpRequestAndAnswer(() -> {
- try {
- Thread.sleep(10_000);
- return groupResponseHolder;
- }
- catch (InterruptedException e) {
- isInterrupted.set(true);
- throw e;
- }
- });
+ expectHttpRequestAndAnswer(
+ "cachedSerializedGroupMappingMap",
+ () -> {
+ try {
+ Thread.sleep(10_000);
+ return groupResponseHolder;
+ }
+ catch (InterruptedException e) {
+ isInterrupted.set(true);
+ throw e;
+ }
+ }
+ );
replayAll();
@@ -183,21 +195,27 @@ public class
CoordinatorPollingBasicAuthorizerCacheManagerTest
verifyAll();
}
- private void expectHttpRequestAndAnswer(IAnswer<BytesFullResponseHolder>
responseHolder)
+ private void expectHttpRequestAndAnswer(String path,
IAnswer<BytesFullResponseHolder> responseHolder)
{
- try {
- EasyMock.expect(
- leaderClient.makeRequest(EasyMock.anyObject(), EasyMock.anyString())
- ).andReturn(request).once();
- EasyMock.expect(
- leaderClient.go(
- EasyMock.anyObject(),
- EasyMock.anyObject(BytesFullResponseHandler.class)
- )
- ).andAnswer(responseHolder).once();
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
+ final String fullPath = StringUtils.format(
+ "/druid-ext/basic-security/authorization/db/%s/%s",
+ AUTHORIZER_NAME, path
+ );
+ serviceClient.expectAndRespond(
+ new RequestBuilder(HttpMethod.GET, fullPath),
+ new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)
+ {
+ @Override
+ public ChannelBuffer getContent()
+ {
+ try {
+ return
ChannelBuffers.wrappedBuffer(responseHolder.answer().getContent());
+ }
+ catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ );
}
}
diff --git a/extensions-core/druid-catalog/pom.xml
b/extensions-core/druid-catalog/pom.xml
index 729bac20861..9bd320c24a7 100644
--- a/extensions-core/druid-catalog/pom.xml
+++ b/extensions-core/druid-catalog/pom.xml
@@ -187,6 +187,11 @@
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.curator</groupId>
+ <artifactId>curator-test</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.apache.druid</groupId>
<artifactId>druid-processing</artifactId>
@@ -201,6 +206,24 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.druid</groupId>
+ <artifactId>druid-services</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.druid</groupId>
+ <artifactId>druid-indexing-service</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency><dependency>
+ <groupId>org.apache.druid</groupId>
+ <artifactId>druid-services</artifactId>
+ <version>${project.parent.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.apache.druid</groupId>
<artifactId>druid-sql</artifactId>
diff --git
a/extensions-core/druid-catalog/src/main/java/org/apache/druid/catalog/sync/CatalogClient.java
b/extensions-core/druid-catalog/src/main/java/org/apache/druid/catalog/sync/CatalogClient.java
index 68bc21d571f..1c3a2be487b 100644
---
a/extensions-core/druid-catalog/src/main/java/org/apache/druid/catalog/sync/CatalogClient.java
+++
b/extensions-core/druid-catalog/src/main/java/org/apache/druid/catalog/sync/CatalogClient.java
@@ -21,67 +21,69 @@ package org.apache.druid.catalog.sync;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.util.concurrent.ListenableFuture;
import org.apache.druid.catalog.http.CatalogResource;
import org.apache.druid.catalog.model.ResolvedTable;
import org.apache.druid.catalog.model.TableDefnRegistry;
import org.apache.druid.catalog.model.TableId;
import org.apache.druid.catalog.model.TableMetadata;
+import org.apache.druid.catalog.model.TableSpec;
import org.apache.druid.client.coordinator.Coordinator;
-import org.apache.druid.discovery.DruidLeaderClient;
-import org.apache.druid.guice.annotations.Json;
-import org.apache.druid.guice.annotations.Smile;
-import org.apache.druid.java.util.common.ISE;
+import org.apache.druid.common.guava.FutureUtils;
+import org.apache.druid.discovery.NodeRole;
+import org.apache.druid.guice.annotations.EscalatedGlobal;
import org.apache.druid.java.util.common.StringUtils;
-import org.apache.druid.java.util.http.client.Request;
-import
org.apache.druid.java.util.http.client.response.StringFullResponseHolder;
-import org.jboss.netty.handler.codec.http.HttpHeaders;
+import org.apache.druid.java.util.common.jackson.JacksonUtils;
+import
org.apache.druid.java.util.http.client.response.BytesFullResponseHandler;
+import org.apache.druid.rpc.IgnoreHttpResponseHandler;
+import org.apache.druid.rpc.RequestBuilder;
+import org.apache.druid.rpc.ServiceClient;
+import org.apache.druid.rpc.ServiceClientFactory;
+import org.apache.druid.rpc.ServiceLocator;
+import org.apache.druid.rpc.StandardRetryPolicy;
+import org.apache.druid.server.http.ServletResourceUtils;
import org.jboss.netty.handler.codec.http.HttpMethod;
-import org.jboss.netty.handler.codec.http.HttpResponseStatus;
+import javax.annotation.Nullable;
import javax.inject.Inject;
-import javax.ws.rs.core.MediaType;
-import java.io.IOException;
import java.util.Collections;
import java.util.List;
/**
- * Guice-injected client for the catalog update sync process. Requests
- * tables and schemas from the catalog component on the Coordinator.
- *
- * This class handles any recoverable error case. If this class throws
- * an exception, then something went very wrong and there is little the
- * caller can do to make things better. All the caller can do is try
- * again later and hope things improve.
+ * Used by Brokers and Overlord to sync the catalog by querying the
Coordinator.
+ * <p>
+ * Modeled after other {@link ServiceClient}-based classes such as {@code
CoordinatorClient}.
*/
public class CatalogClient implements CatalogSource
{
public static final String SCHEMA_SYNC_PATH = CatalogResource.ROOT_PATH +
CatalogResource.SCHEMA_SYNC;
public static final String TABLE_SYNC_PATH = CatalogResource.ROOT_PATH +
CatalogResource.TABLE_SYNC;
- private static final TypeReference<List<TableMetadata>>
LIST_OF_TABLE_METADATA_TYPE = new TypeReference<>() {};
- // Not strictly needed as a TypeReference, but doing so makes the code
simpler.
- private static final TypeReference<TableMetadata> TABLE_METADATA_TYPE = new
TypeReference<>() {};
+ private static final String TABLE_CREATE_PATH = CatalogResource.ROOT_PATH +
"/schemas/{schema}/tables/{name}";
- private final DruidLeaderClient coordClient;
- private final ObjectMapper smileMapper;
+ private final ServiceClient serviceClient;
+ private final ObjectMapper jsonMapper;
private final TableDefnRegistry tableRegistry;
@Inject
public CatalogClient(
- @Coordinator DruidLeaderClient coordClient,
- @Smile ObjectMapper smileMapper,
- @Json ObjectMapper jsonMapper
+ @EscalatedGlobal final ServiceClientFactory clientFactory,
+ @Coordinator final ServiceLocator serviceLocator,
+ ObjectMapper jsonMapper
)
{
- this.coordClient = coordClient;
- this.smileMapper = smileMapper;
+ this.jsonMapper = jsonMapper;
this.tableRegistry = new TableDefnRegistry(jsonMapper);
+ this.serviceClient = clientFactory.makeClient(
+ NodeRole.COORDINATOR.getJsonName(),
+ serviceLocator,
+ StandardRetryPolicy.builder().maxAttempts(6).build()
+ );
}
@Override
public List<TableMetadata> tablesForSchema(String dbSchema)
{
- String url = StringUtils.replace(SCHEMA_SYNC_PATH, "{schema}",
StringUtils.urlEncode(dbSchema));
- List<TableMetadata> results = send(url, LIST_OF_TABLE_METADATA_TYPE);
+ List<TableMetadata> results = getResult(fetchTablesForSchema(dbSchema));
// Not found for a list is an empty list.
return results == null ? Collections.emptyList() : results;
@@ -90,9 +92,7 @@ public class CatalogClient implements CatalogSource
@Override
public TableMetadata table(TableId id)
{
- String url = StringUtils.replace(TABLE_SYNC_PATH, "{schema}",
StringUtils.urlEncode(id.schema()));
- url = StringUtils.replace(url, "{name}", StringUtils.urlEncode(id.name()));
- return send(url, TABLE_METADATA_TYPE);
+ return getResult(fetchTableForId(id));
}
@Override
@@ -103,46 +103,87 @@ public class CatalogClient implements CatalogSource
}
/**
- * Send the update. Exceptions are "unexpected": they should never occur in a
- * working system. If they occur, something is broken.
+ * Creates a table for the given {@link TableId} and {@link TableSpec}.
+ * If a table already exists for this id, it is overwritten.
+ * <p>
+ * This method is currently used only in tests.
+ */
+ public void createTable(TableId tableId, TableSpec tableSpec)
+ {
+ getResult(postCreateTable(tableId, tableSpec));
+ }
+
+ /**
+ * Posts the given table spec to the Coordinator.
+ * <p>
+ * API: {@code POST
/druid/coordinator/v1/catalog/schemas/{schema}/tables/{name}}
+ */
+ private ListenableFuture<Void> postCreateTable(TableId tableId, TableSpec
tableSpec)
+ {
+ String path = StringUtils.replace(TABLE_CREATE_PATH, "{schema}",
StringUtils.urlEncode(tableId.schema()));
+ path = StringUtils.replace(path, "{name}",
StringUtils.urlEncode(tableId.name()));
+
+ return serviceClient.asyncRequest(
+ new RequestBuilder(HttpMethod.POST, path)
+ .jsonContent(jsonMapper, tableSpec),
+ IgnoreHttpResponseHandler.INSTANCE
+ );
+ }
+
+ /**
+ * Fetches the metadata of a table from the Coordinator.
+ * <p>
+ * API: {@code GET
/druid/coordinator/v1/catalog/sync/schemas/{schema}/{name}}
+ */
+ private ListenableFuture<TableMetadata> fetchTableForId(TableId id)
+ {
+ String path = StringUtils.replace(TABLE_SYNC_PATH, "{schema}",
StringUtils.urlEncode(id.schema()));
+ path = StringUtils.replace(path, "{name}",
StringUtils.urlEncode(id.name()));
+
+ return FutureUtils.transform(
+ serviceClient.asyncRequest(
+ new RequestBuilder(HttpMethod.GET, path),
+ new BytesFullResponseHandler()
+ ),
+ holder -> JacksonUtils.readValue(jsonMapper, holder.getContent(),
TableMetadata.class)
+ );
+ }
+
+ /**
+ * Fetches the metadata of all tables in a schema from the Coordinator.
+ * <p>
+ * API: {@code GET /druid/coordinator/v1/catalog/sync/schemas/{schema}}
+ */
+ private ListenableFuture<List<TableMetadata>> fetchTablesForSchema(String
schemaName)
+ {
+ final String path = StringUtils.replace(
+ SCHEMA_SYNC_PATH,
+ "{schema}",
+ StringUtils.urlEncode(schemaName)
+ );
+
+ return FutureUtils.transform(
+ serviceClient.asyncRequest(
+ new RequestBuilder(HttpMethod.GET, path),
+ new BytesFullResponseHandler()
+ ),
+ holder -> JacksonUtils.readValue(jsonMapper, holder.getContent(), new
TypeReference<>() {})
+ );
+ }
+
+ /**
+ * Gets the result from the given future.
*
- * @return the requested update, or null if the item was not found in the
- * catalog.
+ * @return null if the API returns a 404 not found status.
*/
- private <T> T send(String url, TypeReference<T> typeRef)
+ @Nullable
+ private <T> T getResult(ListenableFuture<T> future)
{
- final Request request;
- try {
- request = coordClient.makeRequest(HttpMethod.GET, url)
- .addHeader(HttpHeaders.Names.ACCEPT, MediaType.APPLICATION_JSON);
- }
- catch (IOException e) {
- throw new ISE("Cannot create catalog sync request");
- }
- final StringFullResponseHolder responseHolder;
- try {
- responseHolder = coordClient.go(request);
- }
- catch (IOException e) {
- throw new ISE(e, "Failed to send catalog sync");
- }
- catch (InterruptedException e1) {
- // Treat as a not-found: the only way this exception should occur
- // is during shutdown.
- return null;
- }
- if (responseHolder.getStatus().getCode() ==
HttpResponseStatus.NOT_FOUND.getCode()) {
- // Not found means the item disappeared. Returning null means "not
found".
- return null;
- }
- if (responseHolder.getStatus().getCode() !=
HttpResponseStatus.OK.getCode()) {
- throw new ISE("Unexpected status from catalog sync: " +
responseHolder.getStatus());
- }
try {
- return smileMapper.readValue(responseHolder.getContent(), typeRef);
+ return FutureUtils.getUnchecked(future, true);
}
- catch (IOException e) {
- throw new ISE(e, "Could not decode the JSON response from catalog
sync.");
+ catch (Exception e) {
+ return ServletResourceUtils.getDefaultValueIfCauseIs404ElseThrow(e, ()
-> null);
}
}
}
diff --git
a/extensions-core/druid-catalog/src/test/java/org/apache/druid/catalog/compact/CatalogCompactionTest.java
b/extensions-core/druid-catalog/src/test/java/org/apache/druid/catalog/compact/CatalogCompactionTest.java
new file mode 100644
index 00000000000..d44f3ad6593
--- /dev/null
+++
b/extensions-core/druid-catalog/src/test/java/org/apache/druid/catalog/compact/CatalogCompactionTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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.druid.catalog.compact;
+
+import org.apache.druid.catalog.guice.CatalogClientModule;
+import org.apache.druid.catalog.guice.CatalogCoordinatorModule;
+import org.apache.druid.catalog.model.TableId;
+import org.apache.druid.catalog.model.TableMetadata;
+import org.apache.druid.catalog.model.table.TableBuilder;
+import org.apache.druid.catalog.sync.CatalogClient;
+import org.apache.druid.common.utils.IdUtils;
+import org.apache.druid.indexing.compact.CompactionSupervisorSpec;
+import org.apache.druid.indexing.overlord.Segments;
+import org.apache.druid.java.util.common.StringUtils;
+import org.apache.druid.java.util.common.granularity.Granularities;
+import org.apache.druid.rpc.UpdateResponse;
+import org.apache.druid.server.coordinator.CatalogDataSourceCompactionConfig;
+import org.apache.druid.server.coordinator.ClusterCompactionConfig;
+import org.apache.druid.testing.embedded.EmbeddedBroker;
+import org.apache.druid.testing.embedded.EmbeddedClusterApis;
+import org.apache.druid.testing.embedded.EmbeddedCoordinator;
+import org.apache.druid.testing.embedded.EmbeddedDruidCluster;
+import org.apache.druid.testing.embedded.EmbeddedHistorical;
+import org.apache.druid.testing.embedded.EmbeddedIndexer;
+import org.apache.druid.testing.embedded.EmbeddedOverlord;
+import org.apache.druid.testing.embedded.indexing.Resources;
+import org.apache.druid.testing.embedded.junit5.EmbeddedClusterTestBase;
+import org.apache.druid.timeline.DataSegment;
+import org.joda.time.Period;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+public class CatalogCompactionTest extends EmbeddedClusterTestBase
+{
+ private final EmbeddedOverlord overlord = new EmbeddedOverlord();
+ private final EmbeddedCoordinator coordinator = new EmbeddedCoordinator()
+ .addProperty("druid.manager.segments.useIncrementalCache", "always");
+ private final EmbeddedBroker broker = new EmbeddedBroker()
+ .addProperty("druid.catalog.client.pollingPeriod", "100");
+
+ @Override
+ protected EmbeddedDruidCluster createCluster()
+ {
+ return EmbeddedDruidCluster.withEmbeddedDerbyAndZookeeper()
+ .useLatchableEmitter()
+ .addExtension(CatalogClientModule.class)
+ .addExtension(CatalogCoordinatorModule.class)
+ .addServer(coordinator)
+ .addServer(overlord)
+ .addServer(broker)
+ .addServer(new EmbeddedIndexer())
+ .addServer(new EmbeddedHistorical());
+ }
+
+ @Test
+ public void test_ingestDayGranularity_andCompactToMonthGranularity()
+ {
+ // Ingest data at DAY granularity and verify
+ runIngestionAtDayGranularity();
+ List<DataSegment> segments = List.copyOf(
+ overlord.bindings()
+ .segmentsMetadataStorage()
+ .retrieveAllUsedSegments(dataSource, Segments.ONLY_VISIBLE)
+ );
+ Assertions.assertEquals(10, segments.size());
+ segments.forEach(
+ segment ->
Assertions.assertTrue(Granularities.DAY.isAligned(segment.getInterval()))
+ );
+
+ final CatalogClient catalogClient =
broker.bindings().getInstance(CatalogClient.class);
+
+ // Create a catalog entry to have MONTH granularity for the datasource
+ final TableId tableId = new TableId("druid", dataSource);
+ catalogClient.createTable(
+ tableId,
+ TableBuilder.datasource(dataSource, "P1M").buildSpec()
+ );
+
+ final TableMetadata metadata = catalogClient.table(tableId);
+ Assertions.assertEquals(
+ StringUtils.format("\"druid\".\"%s\"", dataSource),
+ metadata.sqlName()
+ );
+ Assertions.assertEquals(
+ TableBuilder.datasource(dataSource, "P1M").buildSpec(),
+ metadata.spec()
+ );
+
+ enableCompactionSupervisor();
+
+ // Create a catalog compaction config
+ CatalogDataSourceCompactionConfig compactionConfig =
+ new CatalogDataSourceCompactionConfig(dataSource, null, Period.ZERO,
null, null, null, null);
+
+ final CompactionSupervisorSpec compactionSupervisor
+ = new CompactionSupervisorSpec(compactionConfig, false, null);
+ cluster.callApi().onLeaderOverlord(o ->
o.postSupervisor(compactionSupervisor));
+
+ // Wait for compaction to finish
+ overlord.latchableEmitter().waitForEvent(
+ event -> event.hasMetricName("task/run/time")
+ .hasDimension("taskType", "compact")
+ );
+
+ // Verify that segments are now compacted to MONTH granularity
+ segments = List.copyOf(
+ overlord.bindings()
+ .segmentsMetadataStorage()
+ .retrieveAllUsedSegments(dataSource, Segments.ONLY_VISIBLE)
+ );
+ Assertions.assertEquals(1, segments.size());
+ Assertions.assertTrue(
+ Granularities.MONTH.isAligned(segments.get(0).getInterval())
+ );
+ }
+
+ private void runIngestionAtDayGranularity()
+ {
+ final String taskId = IdUtils.getRandomId();
+ final Object task = createIndexTaskForInlineData(
+ taskId,
+ StringUtils.replace(Resources.CSV_DATA_10_DAYS, "\n", "\\n")
+ );
+
+ cluster.callApi().onLeaderOverlord(o -> o.runTask(taskId, task));
+ cluster.callApi().waitForTaskToSucceed(taskId, overlord);
+ }
+
+ private Object createIndexTaskForInlineData(String taskId, String
inlineDataCsv)
+ {
+ return EmbeddedClusterApis.createTaskFromPayload(
+ taskId,
+ StringUtils.format(Resources.INDEX_TASK_PAYLOAD_WITH_INLINE_DATA,
inlineDataCsv, dataSource)
+ );
+ }
+
+ private void enableCompactionSupervisor()
+ {
+ final UpdateResponse updateResponse = cluster.callApi().onLeaderOverlord(
+ o -> o.updateClusterCompactionConfig(new ClusterCompactionConfig(1.0,
10, null, true, null))
+ );
+ Assertions.assertTrue(updateResponse.isSuccess());
+ }
+}
diff --git
a/quidem-ut/src/main/java/org/apache/druid/quidem/ExposedAsBrokerQueryComponentSupplierWrapper.java
b/quidem-ut/src/main/java/org/apache/druid/quidem/ExposedAsBrokerQueryComponentSupplierWrapper.java
index 0a2e496b09a..ede29251aec 100644
---
a/quidem-ut/src/main/java/org/apache/druid/quidem/ExposedAsBrokerQueryComponentSupplierWrapper.java
+++
b/quidem-ut/src/main/java/org/apache/druid/quidem/ExposedAsBrokerQueryComponentSupplierWrapper.java
@@ -41,7 +41,6 @@ import org.apache.druid.curator.discovery.DiscoveryModule;
import org.apache.druid.discovery.DruidNodeDiscoveryProvider;
import org.apache.druid.guice.AnnouncerModule;
import org.apache.druid.guice.BrokerServiceModule;
-import org.apache.druid.guice.CoordinatorDiscoveryModule;
import org.apache.druid.guice.ExpressionModule;
import org.apache.druid.guice.ExtensionsModule;
import org.apache.druid.guice.JacksonConfigManagerModule;
@@ -186,7 +185,6 @@ public class ExposedAsBrokerQueryComponentSupplierWrapper
extends QueryComponent
new MetadataConfigModule(),
new DerbyMetadataStorageDruidModule(),
new JacksonConfigManagerModule(),
- new CoordinatorDiscoveryModule(),
new LocalDataStorageDruidModule(),
new TombstoneDataStorageModule(),
new JavaScriptModule(),
diff --git
a/server/src/main/java/org/apache/druid/discovery/DruidLeaderClient.java
b/server/src/main/java/org/apache/druid/discovery/DruidLeaderClient.java
deleted file mode 100644
index 28e48b29aa4..00000000000
--- a/server/src/main/java/org/apache/druid/discovery/DruidLeaderClient.java
+++ /dev/null
@@ -1,307 +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.druid.discovery;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Throwables;
-import org.apache.druid.concurrent.LifecycleLock;
-import org.apache.druid.java.util.common.IOE;
-import org.apache.druid.java.util.common.ISE;
-import org.apache.druid.java.util.common.RE;
-import org.apache.druid.java.util.common.StringUtils;
-import org.apache.druid.java.util.common.lifecycle.LifecycleStart;
-import org.apache.druid.java.util.common.lifecycle.LifecycleStop;
-import org.apache.druid.java.util.common.logger.Logger;
-import org.apache.druid.java.util.http.client.HttpClient;
-import org.apache.druid.java.util.http.client.Request;
-import org.apache.druid.java.util.http.client.response.FullResponseHolder;
-import org.apache.druid.java.util.http.client.response.HttpResponseHandler;
-import
org.apache.druid.java.util.http.client.response.StringFullResponseHandler;
-import
org.apache.druid.java.util.http.client.response.StringFullResponseHolder;
-import org.jboss.netty.channel.ChannelException;
-import org.jboss.netty.handler.codec.http.HttpMethod;
-import org.jboss.netty.handler.codec.http.HttpResponseStatus;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * This class facilitates interaction with Coordinator/Overlord leader nodes.
Instance of this class is injected
- * via Guice with annotations @Coordinator or @IndexingService .
- * Usage:
- * Request request = druidLeaderClient.makeRequest(HttpMethod, requestPath)
- * request.setXXX(..)
- * FullResponseHolder responseHolder = druidLeaderClient.go(request)
- */
-public class DruidLeaderClient
-{
- private final Logger log = new Logger(DruidLeaderClient.class);
-
- private static final int MAX_RETRIES = 5;
-
- private final HttpClient httpClient;
- private final DruidNodeDiscoveryProvider druidNodeDiscoveryProvider;
- private final NodeRole nodeRoleToWatch;
-
- private final String leaderRequestPath;
-
- private final LifecycleLock lifecycleLock = new LifecycleLock();
- private DruidNodeDiscovery druidNodeDiscovery;
- private final AtomicReference<String> currentKnownLeader = new
AtomicReference<>();
-
- public DruidLeaderClient(
- HttpClient httpClient,
- DruidNodeDiscoveryProvider druidNodeDiscoveryProvider,
- NodeRole nodeRoleToWatch,
- String leaderRequestPath
- )
- {
- this.httpClient = httpClient;
- this.druidNodeDiscoveryProvider = druidNodeDiscoveryProvider;
- this.nodeRoleToWatch = nodeRoleToWatch;
- this.leaderRequestPath = leaderRequestPath;
- }
-
- @LifecycleStart
- public void start()
- {
- if (!lifecycleLock.canStart()) {
- throw new ISE("can't start.");
- }
-
- try {
- druidNodeDiscovery =
druidNodeDiscoveryProvider.getForNodeRole(nodeRoleToWatch);
- lifecycleLock.started();
- log.debug("Started.");
- }
- finally {
- lifecycleLock.exitStart();
- }
- }
-
- @LifecycleStop
- public void stop()
- {
- if (!lifecycleLock.canStop()) {
- throw new ISE("can't stop.");
- }
-
- log.debug("Stopped.");
- }
-
- /**
- * Make a Request object aimed at the leader. Throws IOException if the
leader cannot be located.
- */
- public Request makeRequest(HttpMethod httpMethod, String urlPath) throws
IOException
- {
- Preconditions.checkState(lifecycleLock.awaitStarted(1,
TimeUnit.MILLISECONDS));
- return new Request(httpMethod, new URL(StringUtils.format("%s%s",
getCurrentKnownLeader(true), urlPath)));
- }
-
- /**
- * Executes a Request object aimed at the leader. Throws IOException if the
leader cannot be located.
- * Internal retries with cache invalidation are attempted if 503/504
response is received.
- *
- * @param request
- * @throws IOException
- * @throws InterruptedException
- */
- public StringFullResponseHolder go(Request request) throws IOException,
InterruptedException
- {
- return go(request, new StringFullResponseHandler(StandardCharsets.UTF_8));
- }
-
- /**
- * Executes a Request object aimed at the leader. Throws IOException if the
leader cannot be located.
- * Internal retries with cache invalidation are attempted if 503/504
response is received.
- *
- * @param request
- * @param responseHandler
- * @throws IOException
- * @throws InterruptedException
- */
- public <T, H extends FullResponseHolder<T>> H go(
- Request request,
- HttpResponseHandler<H, H> responseHandler
- )
- throws IOException, InterruptedException
- {
- Preconditions.checkState(lifecycleLock.awaitStarted(1,
TimeUnit.MILLISECONDS));
- for (int counter = 0; counter < MAX_RETRIES; counter++) {
-
- final H fullResponseHolder;
-
- try {
- try {
- fullResponseHolder = httpClient.go(request, responseHandler).get();
- }
- catch (ExecutionException e) {
- // Unwrap IOExceptions and ChannelExceptions, re-throw others
- Throwables.propagateIfInstanceOf(e.getCause(), IOException.class);
- Throwables.propagateIfInstanceOf(e.getCause(),
ChannelException.class);
- throw new RE(e, "HTTP request to[%s] failed", request.getUrl());
- }
- }
- catch (IOException | ChannelException ex) {
- // can happen if the node is stopped.
- log.warn(ex, "Request[%s] failed.", request.getUrl());
- request = getNewRequestUrlInvalidatingCache(request);
- continue;
- }
- HttpResponseStatus responseStatus =
fullResponseHolder.getResponse().getStatus();
- if (HttpResponseStatus.TEMPORARY_REDIRECT.equals(responseStatus)) {
- String redirectUrlStr =
fullResponseHolder.getResponse().headers().get("Location");
- if (redirectUrlStr == null) {
- throw new IOE("No redirect location is found in response from
url[%s].", request.getUrl());
- }
-
- log.info("Request[%s] received redirect response to location [%s].",
request.getUrl(), redirectUrlStr);
-
- final URL redirectUrl;
- try {
- redirectUrl = new URL(redirectUrlStr);
- }
- catch (MalformedURLException ex) {
- throw new IOE(
- ex,
- "Malformed redirect location is found in response from url[%s],
new location[%s].",
- request.getUrl(),
- redirectUrlStr
- );
- }
-
- //update known leader location
- currentKnownLeader.set(StringUtils.format(
- "%s://%s:%s",
- redirectUrl.getProtocol(),
- redirectUrl.getHost(),
- redirectUrl.getPort()
- ));
-
- request = ClientUtils.withUrl(request, redirectUrl);
- } else if (HttpResponseStatus.SERVICE_UNAVAILABLE.equals(responseStatus)
- || HttpResponseStatus.GATEWAY_TIMEOUT.equals(responseStatus))
{
- log.warn(
- "Request[%s] received a %s response. Attempt %s/%s",
- request.getUrl(),
- responseStatus,
- counter + 1,
- MAX_RETRIES
- );
- request = getNewRequestUrlInvalidatingCache(request);
- } else {
- return fullResponseHolder;
- }
- }
-
- throw new IOE("Retries exhausted, couldn't fulfill request to [%s].",
request.getUrl());
- }
-
- public String findCurrentLeader()
- {
- Preconditions.checkState(lifecycleLock.awaitStarted(1,
TimeUnit.MILLISECONDS));
- final StringFullResponseHolder responseHolder;
- try {
- responseHolder = go(makeRequest(HttpMethod.GET, leaderRequestPath));
- }
- catch (Exception ex) {
- throw new ISE(ex, "Couldn't find leader.");
- }
-
- if (responseHolder.getStatus().getCode() == 200) {
- String leaderUrl = responseHolder.getContent();
-
- //verify this is valid url
- try {
- URL validatedUrl = new URL(leaderUrl);
- currentKnownLeader.set(leaderUrl);
-
- // validatedUrl.toString() is returned instead of leaderUrl or else
teamcity build fails because of breaking
- // the rule of ignoring new URL(leaderUrl) object.
- return validatedUrl.toString();
- }
- catch (MalformedURLException ex) {
- log.error(ex, "Received malformed leader url[%s].", leaderUrl);
- }
- }
-
- throw new ISE(
- "Couldn't find leader, failed response status is [%s] and content
[%s].",
- responseHolder.getStatus().getCode(),
- responseHolder.getContent()
- );
- }
-
- private String getCurrentKnownLeader(final boolean cached) throws IOException
- {
- final String leader = currentKnownLeader.accumulateAndGet(
- null,
- (current, given) -> current == null || !cached ?
ClientUtils.pickOneHost(druidNodeDiscovery) : current
- );
-
- if (leader == null) {
- throw new IOE(
- "A leader node could not be found for [%s] service. "
- + "Check logs of service [%s] to confirm it is healthy.",
- nodeRoleToWatch, nodeRoleToWatch
- );
- } else {
- return leader;
- }
- }
-
- private Request getNewRequestUrlInvalidatingCache(Request oldRequest) throws
IOException
- {
- try {
- Request newRequest;
- if (oldRequest.getUrl().getQuery() == null) {
- newRequest = ClientUtils.withUrl(
- oldRequest,
- new URL(StringUtils.format("%s%s", getCurrentKnownLeader(false),
oldRequest.getUrl().getPath()))
- );
- } else {
- newRequest = ClientUtils.withUrl(
- oldRequest,
- new URL(StringUtils.format(
- "%s%s?%s",
- getCurrentKnownLeader(false),
- oldRequest.getUrl().getPath(),
- oldRequest.getUrl().getQuery()
- ))
- );
- }
- return newRequest;
- }
- catch (MalformedURLException e) {
- // Not an IOException; this is our own fault.
- throw new ISE(
- e,
- "failed to build url with path[%] and query string [%s].",
- oldRequest.getUrl().getPath(),
- oldRequest.getUrl().getQuery()
- );
- }
- }
-}
diff --git
a/server/src/main/java/org/apache/druid/guice/CoordinatorDiscoveryModule.java
b/server/src/main/java/org/apache/druid/guice/CoordinatorDiscoveryModule.java
deleted file mode 100644
index d9f083767df..00000000000
---
a/server/src/main/java/org/apache/druid/guice/CoordinatorDiscoveryModule.java
+++ /dev/null
@@ -1,58 +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.druid.guice;
-
-import com.google.inject.Binder;
-import com.google.inject.Module;
-import com.google.inject.Provides;
-import org.apache.druid.client.coordinator.Coordinator;
-import org.apache.druid.client.coordinator.CoordinatorSelectorConfig;
-import org.apache.druid.discovery.DruidLeaderClient;
-import org.apache.druid.discovery.DruidNodeDiscoveryProvider;
-import org.apache.druid.discovery.NodeRole;
-import org.apache.druid.guice.annotations.EscalatedGlobal;
-import org.apache.druid.java.util.http.client.HttpClient;
-
-/**
- */
-public class CoordinatorDiscoveryModule implements Module
-{
- @Override
- public void configure(Binder binder)
- {
- JsonConfigProvider.bind(binder, "druid.selectors.coordinator",
CoordinatorSelectorConfig.class);
- }
-
- @Provides
- @Coordinator
- @ManageLifecycle
- public DruidLeaderClient getLeaderHttpClient(
- @EscalatedGlobal HttpClient httpClient,
- DruidNodeDiscoveryProvider druidNodeDiscoveryProvider
- )
- {
- return new DruidLeaderClient(
- httpClient,
- druidNodeDiscoveryProvider,
- NodeRole.COORDINATOR,
- "/druid/coordinator/v1/leader"
- );
- }
-}
diff --git
a/server/src/main/java/org/apache/druid/initialization/CoreInjectorBuilder.java
b/server/src/main/java/org/apache/druid/initialization/CoreInjectorBuilder.java
index caef8be64b1..602fe4ec3d2 100644
---
a/server/src/main/java/org/apache/druid/initialization/CoreInjectorBuilder.java
+++
b/server/src/main/java/org/apache/druid/initialization/CoreInjectorBuilder.java
@@ -26,7 +26,6 @@ import org.apache.druid.discovery.NodeRole;
import org.apache.druid.guice.AnnouncerModule;
import org.apache.druid.guice.BuiltInTypesModule;
import org.apache.druid.guice.CatalogCoreModule;
-import org.apache.druid.guice.CoordinatorDiscoveryModule;
import org.apache.druid.guice.DruidInjectorBuilder;
import org.apache.druid.guice.DruidSecondaryModule;
import org.apache.druid.guice.ExpressionModule;
@@ -122,7 +121,6 @@ public class CoreInjectorBuilder extends
DruidInjectorBuilder
new MetadataConfigModule(),
new DerbyMetadataStorageDruidModule(),
new JacksonConfigManagerModule(),
- new CoordinatorDiscoveryModule(),
new LocalDataStorageDruidModule(),
new TombstoneDataStorageModule(),
new JavaScriptModule(),
diff --git
a/server/src/main/java/org/apache/druid/query/lookup/LookupReferencesManager.java
b/server/src/main/java/org/apache/druid/query/lookup/LookupReferencesManager.java
index cef7d9eaa29..94c333122b7 100644
---
a/server/src/main/java/org/apache/druid/query/lookup/LookupReferencesManager.java
+++
b/server/src/main/java/org/apache/druid/query/lookup/LookupReferencesManager.java
@@ -24,7 +24,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
-import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Inject;
@@ -41,10 +40,9 @@ import org.apache.druid.java.util.common.concurrent.Execs;
import org.apache.druid.java.util.common.lifecycle.LifecycleStart;
import org.apache.druid.java.util.common.lifecycle.LifecycleStop;
import org.apache.druid.java.util.emitter.EmittingLogger;
-import org.apache.druid.rpc.HttpResponseException;
+import org.apache.druid.server.http.ServletResourceUtils;
import org.apache.druid.server.lookup.cache.LookupLoadingSpec;
import org.apache.druid.server.metrics.DataSourceTaskIdHolder;
-import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import javax.annotation.Nullable;
import java.io.File;
@@ -475,19 +473,13 @@ public class LookupReferencesManager implements
LookupExtractorFactoryContainerP
return coordinatorClient.fetchLookupsForTierSync(tier);
}
catch (Exception e) {
- Throwable rootCause = Throwables.getRootCause(e);
- if (rootCause instanceof HttpResponseException) {
- final HttpResponseException httpException = (HttpResponseException)
rootCause;
- if
(httpException.getResponse().getStatus().equals(HttpResponseStatus.NOT_FOUND)) {
- LOG.info(
- "No lookups found for tier [%s], status [%s]",
- tier,
- httpException.getResponse().getStatus()
- );
- return null;
- }
- }
- throw e;
+ return ServletResourceUtils.getDefaultValueIfCauseIs404ElseThrow(
+ e,
+ () -> {
+ LOG.info("No lookups found for tier[%s], status [404, Not Found]",
tier);
+ return null;
+ }
+ );
}
}
diff --git
a/server/src/main/java/org/apache/druid/server/http/ServletResourceUtils.java
b/server/src/main/java/org/apache/druid/server/http/ServletResourceUtils.java
index 04465b677bf..91c59304bfb 100644
---
a/server/src/main/java/org/apache/druid/server/http/ServletResourceUtils.java
+++
b/server/src/main/java/org/apache/druid/server/http/ServletResourceUtils.java
@@ -26,6 +26,8 @@ import org.apache.druid.error.ErrorResponse;
import org.apache.druid.error.InternalServerError;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.java.util.common.logger.Logger;
+import org.apache.druid.rpc.HttpResponseException;
+import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import javax.annotation.Nullable;
import javax.ws.rs.core.MediaType;
@@ -89,4 +91,25 @@ public class ServletResourceUtils
);
}
}
+
+ /**
+ * Returns the given default value if the root cause of the exception is an
+ * {@link HttpResponseException} with status code {@link
HttpResponseStatus#NOT_FOUND}.
+ * Otherwise, re-throws the given exception wrapped in a {@link
RuntimeException}.
+ */
+ public static <T> T getDefaultValueIfCauseIs404ElseThrow(
+ Exception e,
+ Supplier<T> defaultValueSupplier
+ )
+ {
+ Throwable rootCause = Throwables.getRootCause(e);
+ if (rootCause instanceof HttpResponseException) {
+ final HttpResponseException httpException = (HttpResponseException)
rootCause;
+ if
(httpException.getResponse().getStatus().equals(HttpResponseStatus.NOT_FOUND)) {
+ return defaultValueSupplier.get();
+ }
+ }
+
+ throw new RuntimeException(e);
+ }
}
diff --git
a/server/src/test/java/org/apache/druid/discovery/DruidLeaderClientTest.java
b/server/src/test/java/org/apache/druid/discovery/DruidLeaderClientTest.java
deleted file mode 100644
index 4d9870c6e6e..00000000000
--- a/server/src/test/java/org/apache/druid/discovery/DruidLeaderClientTest.java
+++ /dev/null
@@ -1,338 +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.druid.discovery;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.util.concurrent.ListenableFutureTask;
-import com.google.inject.Binder;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.inject.Key;
-import com.google.inject.Module;
-import com.google.inject.name.Named;
-import com.google.inject.name.Names;
-import com.google.inject.servlet.GuiceFilter;
-import org.apache.druid.guice.GuiceInjectors;
-import org.apache.druid.guice.Jerseys;
-import org.apache.druid.guice.JsonConfigProvider;
-import org.apache.druid.guice.LazySingleton;
-import org.apache.druid.guice.LifecycleModule;
-import org.apache.druid.guice.annotations.Self;
-import org.apache.druid.initialization.Initialization;
-import org.apache.druid.java.util.common.StringUtils;
-import org.apache.druid.java.util.http.client.HttpClient;
-import org.apache.druid.java.util.http.client.Request;
-import
org.apache.druid.java.util.http.client.response.StringFullResponseHolder;
-import org.apache.druid.server.DruidNode;
-import org.apache.druid.server.initialization.BaseJettyTest;
-import org.apache.druid.server.initialization.jetty.JettyServerInitializer;
-import org.easymock.EasyMock;
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.HandlerList;
-import org.eclipse.jetty.servlet.DefaultServlet;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
-import org.jboss.netty.handler.codec.http.HttpMethod;
-import org.jboss.netty.handler.codec.http.HttpResponseStatus;
-import org.jboss.netty.handler.codec.http.HttpVersion;
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.mockito.ArgumentMatchers;
-import org.mockito.Mockito;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.io.IOException;
-import java.net.URI;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-
-/**
- */
-@SuppressWarnings("DoNotMock")
-public class DruidLeaderClientTest extends BaseJettyTest
-{
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- private DiscoveryDruidNode discoveryDruidNode;
- private HttpClient httpClient;
-
- @Override
- protected Injector setupInjector()
- {
- final DruidNode node = new DruidNode("test", "localhost", false, null,
null, true, false);
- discoveryDruidNode = new DiscoveryDruidNode(node, NodeRole.PEON,
ImmutableMap.of());
-
- Injector injector = Initialization.makeInjectorWithModules(
- GuiceInjectors.makeStartupInjector(), ImmutableList.<Module>of(
- new Module()
- {
- @Override
- public void configure(Binder binder)
- {
- JsonConfigProvider.bindInstance(
- binder,
- Key.get(DruidNode.class, Self.class),
- node
- );
-
binder.bind(Integer.class).annotatedWith(Names.named("port")).toInstance(node.getPlaintextPort());
-
binder.bind(JettyServerInitializer.class).to(TestJettyServerInitializer.class).in(LazySingleton.class);
- Jerseys.addResource(binder, SimpleResource.class);
- LifecycleModule.register(binder, Server.class);
- }
- }
- )
- );
- httpClient = injector.getInstance(ClientHolder.class).getClient();
- return injector;
- }
-
- @Test
- public void testSimple() throws Exception
- {
- DruidNodeDiscovery druidNodeDiscovery =
EasyMock.createMock(DruidNodeDiscovery.class);
- EasyMock.expect(druidNodeDiscovery.getAllNodes()).andReturn(
- ImmutableList.of(discoveryDruidNode)
- );
-
- DruidNodeDiscoveryProvider druidNodeDiscoveryProvider =
EasyMock.createMock(DruidNodeDiscoveryProvider.class);
-
EasyMock.expect(druidNodeDiscoveryProvider.getForNodeRole(NodeRole.PEON)).andReturn(druidNodeDiscovery);
-
- EasyMock.replay(druidNodeDiscovery, druidNodeDiscoveryProvider);
-
- DruidLeaderClient druidLeaderClient = new DruidLeaderClient(
- httpClient,
- druidNodeDiscoveryProvider,
- NodeRole.PEON,
- "/simple/leader"
- );
- druidLeaderClient.start();
-
- Request request = druidLeaderClient.makeRequest(HttpMethod.POST,
"/simple/direct");
- request.setContent("hello".getBytes(StandardCharsets.UTF_8));
- Assert.assertEquals("hello", druidLeaderClient.go(request).getContent());
- }
-
- @Test
- public void testNoLeaderFound() throws Exception
- {
- DruidNodeDiscovery druidNodeDiscovery =
EasyMock.createMock(DruidNodeDiscovery.class);
-
EasyMock.expect(druidNodeDiscovery.getAllNodes()).andReturn(ImmutableList.of());
-
- DruidNodeDiscoveryProvider druidNodeDiscoveryProvider =
EasyMock.createMock(DruidNodeDiscoveryProvider.class);
-
EasyMock.expect(druidNodeDiscoveryProvider.getForNodeRole(NodeRole.PEON)).andReturn(druidNodeDiscovery);
-
- EasyMock.replay(druidNodeDiscovery, druidNodeDiscoveryProvider);
-
- DruidLeaderClient druidLeaderClient = new DruidLeaderClient(
- httpClient,
- druidNodeDiscoveryProvider,
- NodeRole.PEON,
- "/simple/leader"
- );
- druidLeaderClient.start();
-
- expectedException.expect(IOException.class);
- expectedException.expectMessage(
- "A leader node could not be found for [PEON] service. "
- + "Check logs of service [PEON] to confirm it is healthy.");
- druidLeaderClient.makeRequest(HttpMethod.POST, "/simple/direct");
- }
-
- @Test
- public void testRedirection() throws Exception
- {
- DruidNodeDiscovery druidNodeDiscovery =
EasyMock.createMock(DruidNodeDiscovery.class);
- EasyMock.expect(druidNodeDiscovery.getAllNodes()).andReturn(
- ImmutableList.of(discoveryDruidNode)
- );
-
- DruidNodeDiscoveryProvider druidNodeDiscoveryProvider =
EasyMock.createMock(DruidNodeDiscoveryProvider.class);
-
EasyMock.expect(druidNodeDiscoveryProvider.getForNodeRole(NodeRole.PEON)).andReturn(druidNodeDiscovery);
-
- EasyMock.replay(druidNodeDiscovery, druidNodeDiscoveryProvider);
-
- DruidLeaderClient druidLeaderClient = new DruidLeaderClient(
- httpClient,
- druidNodeDiscoveryProvider,
- NodeRole.PEON,
- "/simple/leader"
- );
- druidLeaderClient.start();
-
- Request request = druidLeaderClient.makeRequest(HttpMethod.POST,
"/simple/redirect");
- request.setContent("hello".getBytes(StandardCharsets.UTF_8));
- Assert.assertEquals("hello", druidLeaderClient.go(request).getContent());
- }
-
- @Test
- public void testServerFailureAndRedirect() throws Exception
- {
- DruidNodeDiscovery druidNodeDiscovery =
EasyMock.createMock(DruidNodeDiscovery.class);
- DiscoveryDruidNode dummyNode = new DiscoveryDruidNode(
- new DruidNode("test", "dummyhost", false, 64231, null, true, false),
- NodeRole.PEON,
- ImmutableMap.of()
- );
-
EasyMock.expect(druidNodeDiscovery.getAllNodes()).andReturn(ImmutableList.of(dummyNode));
-
EasyMock.expect(druidNodeDiscovery.getAllNodes()).andReturn(ImmutableList.of(discoveryDruidNode));
-
- DruidNodeDiscoveryProvider druidNodeDiscoveryProvider =
EasyMock.createMock(DruidNodeDiscoveryProvider.class);
-
EasyMock.expect(druidNodeDiscoveryProvider.getForNodeRole(NodeRole.PEON)).andReturn(druidNodeDiscovery).anyTimes();
-
- EasyMock.replay(druidNodeDiscovery, druidNodeDiscoveryProvider);
-
- DruidLeaderClient druidLeaderClient = new DruidLeaderClient(
- httpClient,
- druidNodeDiscoveryProvider,
- NodeRole.PEON,
- "/simple/leader"
- );
- druidLeaderClient.start();
-
- Request request = druidLeaderClient.makeRequest(HttpMethod.POST,
"/simple/redirect");
- request.setContent("hello".getBytes(StandardCharsets.UTF_8));
- Assert.assertEquals("hello", druidLeaderClient.go(request).getContent());
- }
-
- @Test
- public void test503ResponseFromServerAndCacheRefresh() throws Exception
- {
- DruidNodeDiscovery druidNodeDiscovery =
EasyMock.createMock(DruidNodeDiscovery.class);
- // Should be called twice. Second time is when we refresh the cache since
we get 503 in the first request
-
EasyMock.expect(druidNodeDiscovery.getAllNodes()).andReturn(ImmutableList.of(discoveryDruidNode)).times(2);
-
- DruidNodeDiscoveryProvider druidNodeDiscoveryProvider =
EasyMock.createMock(DruidNodeDiscoveryProvider.class);
-
EasyMock.expect(druidNodeDiscoveryProvider.getForNodeRole(NodeRole.PEON)).andReturn(druidNodeDiscovery).anyTimes();
-
- ListenableFutureTask task =
EasyMock.createMock(ListenableFutureTask.class);
- EasyMock.expect(task.get()).andReturn(new StringFullResponseHolder(new
DefaultHttpResponse(
- HttpVersion.HTTP_1_1,
- HttpResponseStatus.SERVICE_UNAVAILABLE
- ), Charset.defaultCharset()));
- EasyMock.replay(druidNodeDiscovery, druidNodeDiscoveryProvider, task);
-
- HttpClient spyHttpClient = Mockito.spy(this.httpClient);
- // Override behavior for the first call only
-
Mockito.doReturn(task).doCallRealMethod().when(spyHttpClient).go(ArgumentMatchers.any(),
ArgumentMatchers.any());
-
- DruidLeaderClient druidLeaderClient = new DruidLeaderClient(
- spyHttpClient,
- druidNodeDiscoveryProvider,
- NodeRole.PEON,
- "/simple/leader"
- );
- druidLeaderClient.start();
-
- Request request = druidLeaderClient.makeRequest(HttpMethod.POST,
"/simple/direct");
- request.setContent("hello".getBytes(StandardCharsets.UTF_8));
- Assert.assertEquals("hello", druidLeaderClient.go(request).getContent());
- EasyMock.verify(druidNodeDiscovery);
- }
-
- @Test
- public void testFindCurrentLeader()
- {
- DruidNodeDiscovery druidNodeDiscovery =
EasyMock.createMock(DruidNodeDiscovery.class);
- EasyMock.expect(druidNodeDiscovery.getAllNodes()).andReturn(
- ImmutableList.of(discoveryDruidNode)
- );
-
- DruidNodeDiscoveryProvider druidNodeDiscoveryProvider =
EasyMock.createMock(DruidNodeDiscoveryProvider.class);
-
EasyMock.expect(druidNodeDiscoveryProvider.getForNodeRole(NodeRole.PEON)).andReturn(druidNodeDiscovery);
-
- EasyMock.replay(druidNodeDiscovery, druidNodeDiscoveryProvider);
-
- DruidLeaderClient druidLeaderClient = new DruidLeaderClient(
- httpClient,
- druidNodeDiscoveryProvider,
- NodeRole.PEON,
- "/simple/leader"
- );
- druidLeaderClient.start();
-
- Assert.assertEquals("http://localhost:1234/",
druidLeaderClient.findCurrentLeader());
- }
-
- static class TestJettyServerInitializer implements JettyServerInitializer
- {
- @Override
- public void initialize(Server server, Injector injector)
- {
- final ServletContextHandler root = new
ServletContextHandler(ServletContextHandler.SESSIONS);
- root.addServlet(new ServletHolder(new DefaultServlet()), "/*");
- root.addFilter(GuiceFilter.class, "/*", null);
-
- final HandlerList handlerList = new HandlerList();
- handlerList.setHandlers(new Handler[]{root});
- server.setHandler(handlerList);
- }
- }
-
- @Path("/simple")
- public static class SimpleResource
- {
- private final int port;
-
- @Inject
- public SimpleResource(@Named("port") int port)
- {
- this.port = port;
- }
-
- @POST
- @Path("/direct")
- @Produces(MediaType.APPLICATION_JSON)
- public Response direct(String input)
- {
- if ("hello".equals(input)) {
- return Response.ok("hello").build();
- } else {
- return Response.serverError().build();
- }
- }
-
- @POST
- @Path("/redirect")
- @Produces(MediaType.APPLICATION_JSON)
- public Response redirecting() throws Exception
- {
- return Response.temporaryRedirect(new
URI(StringUtils.format("http://localhost:%s/simple/direct", port))).build();
- }
-
- @GET
- @Path("/leader")
- @Produces(MediaType.APPLICATION_JSON)
- public Response leader()
- {
- return Response.ok("http://localhost:1234/").build();
- }
- }
-}
diff --git
a/server/src/test/java/org/apache/druid/server/http/ServletResourceUtilsTest.java
b/server/src/test/java/org/apache/druid/server/http/ServletResourceUtilsTest.java
index 0af66bf0df5..ddbc3d4376f 100644
---
a/server/src/test/java/org/apache/druid/server/http/ServletResourceUtilsTest.java
+++
b/server/src/test/java/org/apache/druid/server/http/ServletResourceUtilsTest.java
@@ -23,11 +23,18 @@ import org.apache.druid.error.DruidException;
import org.apache.druid.error.DruidExceptionMatcher;
import org.apache.druid.error.ErrorResponse;
import org.apache.druid.error.InvalidInput;
+import org.apache.druid.java.util.common.ISE;
+import
org.apache.druid.java.util.http.client.response.StringFullResponseHolder;
+import org.apache.druid.rpc.HttpResponseException;
import org.hamcrest.MatcherAssert;
+import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
+import org.jboss.netty.handler.codec.http.HttpResponseStatus;
+import org.jboss.netty.handler.codec.http.HttpVersion;
import org.junit.Assert;
import org.junit.Test;
import javax.ws.rs.core.Response;
+import java.nio.charset.StandardCharsets;
public class ServletResourceUtilsTest
{
@@ -62,4 +69,37 @@ public class ServletResourceUtilsTest
DruidExceptionMatcher.invalidInput().expectMessageIs("Invalid value of
[inputKey]")
);
}
+
+ @Test
+ public void test_getDefaultValueIfCauseIs404ElseThrow()
+ {
+ final StringFullResponseHolder notFoundResponseHolder = new
StringFullResponseHolder(
+ new DefaultHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.NOT_FOUND),
+ StandardCharsets.UTF_8
+ );
+ Assert.assertEquals(
+ "abc",
+ ServletResourceUtils.getDefaultValueIfCauseIs404ElseThrow(
+ new ISE(new HttpResponseException(notFoundResponseHolder), ""),
+ () -> "abc"
+ )
+ );
+
+ final StringFullResponseHolder badRequestResponseHolder = new
StringFullResponseHolder(
+ new DefaultHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.BAD_REQUEST),
+ StandardCharsets.UTF_8
+ );
+ Assert.assertThrows(
+ RuntimeException.class,
+ () -> ServletResourceUtils.getDefaultValueIfCauseIs404ElseThrow(
+ new ISE(new HttpResponseException(badRequestResponseHolder), ""),
+ () -> "abc"
+ )
+ );
+
+ Assert.assertThrows(
+ RuntimeException.class,
+ () -> ServletResourceUtils.getDefaultValueIfCauseIs404ElseThrow(new
ISE(""), () -> "abc")
+ );
+ }
}
diff --git
a/services/src/test/java/org/apache/druid/testing/embedded/ServerReferenceHolder.java
b/services/src/test/java/org/apache/druid/testing/embedded/ServerReferenceHolder.java
index d36d85693b1..2e878621afe 100644
---
a/services/src/test/java/org/apache/druid/testing/embedded/ServerReferenceHolder.java
+++
b/services/src/test/java/org/apache/druid/testing/embedded/ServerReferenceHolder.java
@@ -21,6 +21,7 @@ package org.apache.druid.testing.embedded;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.inject.Inject;
+import com.google.inject.Injector;
import org.apache.druid.client.broker.BrokerClient;
import org.apache.druid.client.coordinator.Coordinator;
import org.apache.druid.client.coordinator.CoordinatorClient;
@@ -87,6 +88,9 @@ public final class ServerReferenceHolder implements
ServerReferencesProvider
@Json
private ObjectMapper jsonMapper;
+ @Inject
+ private Injector injector;
+
@Override
public DruidNode selfNode()
{
@@ -158,4 +162,10 @@ public final class ServerReferenceHolder implements
ServerReferencesProvider
{
return jsonMapper;
}
+
+ @Override
+ public <T> T getInstance(Class<T> clazz)
+ {
+ return injector.getInstance(clazz);
+ }
}
diff --git
a/services/src/test/java/org/apache/druid/testing/embedded/ServerReferencesProvider.java
b/services/src/test/java/org/apache/druid/testing/embedded/ServerReferencesProvider.java
index 6eeed490e1e..ca24218e0fb 100644
---
a/services/src/test/java/org/apache/druid/testing/embedded/ServerReferencesProvider.java
+++
b/services/src/test/java/org/apache/druid/testing/embedded/ServerReferencesProvider.java
@@ -99,4 +99,10 @@ public interface ServerReferencesProvider
* {@link ObjectMapper} annotated with {@link Json}.
*/
ObjectMapper jsonMapper();
+
+ /**
+ * Gets the injected instance of the object of the specified type.
+ * The returned object must be used for read-only purposes.
+ */
+ <T> T getInstance(Class<T> clazz);
}
diff --git
a/embedded-tests/src/test/java/org/apache/druid/testing/embedded/indexing/Resources.java
b/services/src/test/java/org/apache/druid/testing/embedded/indexing/Resources.java
similarity index 100%
rename from
embedded-tests/src/test/java/org/apache/druid/testing/embedded/indexing/Resources.java
rename to
services/src/test/java/org/apache/druid/testing/embedded/indexing/Resources.java
diff --git
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
index f103e7dbe70..76e6f37ab59 100644
--- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
+++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
@@ -20,8 +20,6 @@
package org.apache.druid.sql.calcite.schema;
import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
@@ -29,7 +27,6 @@ import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.Futures;
import com.google.inject.Inject;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
@@ -49,24 +46,18 @@ import org.apache.calcite.schema.impl.AbstractTable;
import org.apache.druid.client.DruidServer;
import org.apache.druid.client.FilteredServerInventoryView;
import org.apache.druid.client.ImmutableDruidServer;
-import org.apache.druid.client.JsonParserIterator;
import org.apache.druid.client.TimelineServerView;
import org.apache.druid.client.coordinator.CoordinatorClient;
import org.apache.druid.common.guava.FutureUtils;
import org.apache.druid.discovery.DataNodeService;
import org.apache.druid.discovery.DiscoveryDruidNode;
-import org.apache.druid.discovery.DruidLeaderClient;
import org.apache.druid.discovery.DruidNodeDiscoveryProvider;
import org.apache.druid.discovery.NodeRole;
import org.apache.druid.indexer.TaskStatusPlus;
import org.apache.druid.indexing.overlord.supervisor.SupervisorStatus;
import org.apache.druid.java.util.common.ISE;
-import org.apache.druid.java.util.common.RE;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.java.util.common.parsers.CloseableIterator;
-import org.apache.druid.java.util.http.client.Request;
-import
org.apache.druid.java.util.http.client.response.InputStreamFullResponseHandler;
-import
org.apache.druid.java.util.http.client.response.InputStreamFullResponseHolder;
import org.apache.druid.rpc.indexing.OverlordClient;
import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.column.RowSignature;
@@ -86,10 +77,8 @@ import org.apache.druid.sql.calcite.table.RowSignatures;
import org.apache.druid.timeline.DataSegment;
import org.apache.druid.timeline.SegmentId;
import org.apache.druid.timeline.SegmentStatusInCluster;
-import org.jboss.netty.handler.codec.http.HttpMethod;
import javax.annotation.Nullable;
-import javax.servlet.http.HttpServletResponse;
import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
@@ -1057,50 +1046,6 @@ public class SystemSchema extends AbstractSchema
}
}
- public static <T> JsonParserIterator<T> getThingsFromLeaderNode(
- String query,
- TypeReference<T> typeRef,
- DruidLeaderClient leaderClient,
- ObjectMapper jsonMapper
- )
- {
- Request request;
- InputStreamFullResponseHolder responseHolder;
- try {
- request = leaderClient.makeRequest(
- HttpMethod.GET,
- query
- );
-
- responseHolder = leaderClient.go(
- request,
- new InputStreamFullResponseHandler()
- );
-
- if (responseHolder.getStatus().getCode() != HttpServletResponse.SC_OK) {
- throw new RE(
- "Failed to talk to leader node at [%s]. Error code [%d],
description [%s].",
- query,
- responseHolder.getStatus().getCode(),
- responseHolder.getStatus().getReasonPhrase()
- );
- }
- }
- catch (IOException | InterruptedException e) {
- throw new RuntimeException(e);
- }
-
- final JavaType javaType =
jsonMapper.getTypeFactory().constructType(typeRef);
- return new JsonParserIterator<>(
- javaType,
- Futures.immediateFuture(responseHolder.getContent()),
- request.getUrl().toString(),
- null,
- request.getUrl().getHost(),
- jsonMapper
- );
- }
-
private static <T> CloseableIterator<T> wrap(Iterator<T> iterator, Closeable
closer)
{
return new CloseableIterator<>()
diff --git
a/sql/src/test/java/org/apache/druid/sql/calcite/schema/DruidCalciteSchemaModuleTest.java
b/sql/src/test/java/org/apache/druid/sql/calcite/schema/DruidCalciteSchemaModuleTest.java
index 6b4153de28b..23335615409 100644
---
a/sql/src/test/java/org/apache/druid/sql/calcite/schema/DruidCalciteSchemaModuleTest.java
+++
b/sql/src/test/java/org/apache/druid/sql/calcite/schema/DruidCalciteSchemaModuleTest.java
@@ -30,11 +30,8 @@ import com.google.inject.TypeLiteral;
import com.google.inject.name.Names;
import org.apache.druid.client.FilteredServerInventoryView;
import org.apache.druid.client.TimelineServerView;
-import org.apache.druid.client.coordinator.Coordinator;
import org.apache.druid.client.coordinator.CoordinatorClient;
import org.apache.druid.client.coordinator.NoopCoordinatorClient;
-import org.apache.druid.client.indexing.IndexingService;
-import org.apache.druid.discovery.DruidLeaderClient;
import org.apache.druid.discovery.DruidNodeDiscoveryProvider;
import org.apache.druid.guice.LazySingleton;
import org.apache.druid.guice.LifecycleModule;
@@ -87,10 +84,6 @@ public class DruidCalciteSchemaModuleTest extends
CalciteTestBase
@Mock
private FilteredServerInventoryView serverInventoryView;
@Mock
- private DruidLeaderClient coordinatorDruidLeaderClient;
- @Mock
- private DruidLeaderClient overlordDruidLeaderClient;
- @Mock
private DruidNodeDiscoveryProvider druidNodeDiscoveryProvider;
@Mock
private ObjectMapper objectMapper;
@@ -121,12 +114,6 @@ public class DruidCalciteSchemaModuleTest extends
CalciteTestBase
binder.bind(FilteredServerInventoryView.class).toInstance(serverInventoryView);
binder.bind(SegmentManager.class).toInstance(segmentManager);
binder.bind(DruidOperatorTable.class).toInstance(druidOperatorTable);
- binder.bind(DruidLeaderClient.class)
- .annotatedWith(Coordinator.class)
- .toInstance(coordinatorDruidLeaderClient);
- binder.bind(DruidLeaderClient.class)
- .annotatedWith(IndexingService.class)
- .toInstance(overlordDruidLeaderClient);
binder.bind(DruidNodeDiscoveryProvider.class).toInstance(druidNodeDiscoveryProvider);
binder.bind(DruidSchemaManager.class).toInstance(new
NoopDruidSchemaManager());
binder.bind(ObjectMapper.class).annotatedWith(Json.class).toInstance(objectMapper);
diff --git a/sql/src/test/java/org/apache/druid/sql/guice/SqlModuleTest.java
b/sql/src/test/java/org/apache/druid/sql/guice/SqlModuleTest.java
index 2dbb1a0bee1..08c7a0ea8cc 100644
--- a/sql/src/test/java/org/apache/druid/sql/guice/SqlModuleTest.java
+++ b/sql/src/test/java/org/apache/druid/sql/guice/SqlModuleTest.java
@@ -29,11 +29,8 @@ import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import org.apache.druid.client.FilteredServerInventoryView;
import org.apache.druid.client.TimelineServerView;
-import org.apache.druid.client.coordinator.Coordinator;
import org.apache.druid.client.coordinator.CoordinatorClient;
import org.apache.druid.client.coordinator.NoopCoordinatorClient;
-import org.apache.druid.client.indexing.IndexingService;
-import org.apache.druid.discovery.DruidLeaderClient;
import org.apache.druid.discovery.DruidNodeDiscoveryProvider;
import org.apache.druid.guice.DruidGuiceExtensions;
import org.apache.druid.guice.JsonConfigurator;
@@ -98,9 +95,6 @@ public class SqlModuleTest
@Mock
private TimelineServerView timelineServerView;
- @Mock
- private DruidLeaderClient druidLeaderClient;
-
@Mock
private DruidNodeDiscoveryProvider druidNodeDiscoveryProvider;
@@ -134,7 +128,6 @@ public class SqlModuleTest
serviceEmitter,
inventoryView,
timelineServerView,
- druidLeaderClient,
druidNodeDiscoveryProvider,
genericQueryMetricsFactory,
querySegmentWalker,
@@ -201,8 +194,6 @@ public class SqlModuleTest
binder.bind(new
TypeLiteral<Supplier<DefaultQueryConfig>>(){}).toInstance(Suppliers.ofInstance(new
DefaultQueryConfig(null)));
binder.bind(FilteredServerInventoryView.class).toInstance(inventoryView);
binder.bind(TimelineServerView.class).toInstance(timelineServerView);
-
binder.bind(DruidLeaderClient.class).annotatedWith(Coordinator.class).toInstance(druidLeaderClient);
-
binder.bind(DruidLeaderClient.class).annotatedWith(IndexingService.class).toInstance(druidLeaderClient);
binder.bind(DruidNodeDiscoveryProvider.class).toInstance(druidNodeDiscoveryProvider);
binder.bind(GenericQueryMetricsFactory.class).toInstance(genericQueryMetricsFactory);
binder.bind(QuerySegmentWalker.class).toInstance(querySegmentWalker);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]