From 983d9998ed377a954af47a37b3124a467f1ce64b Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Thu, 10 Apr 2025 14:23:30 +0530 Subject: [PATCH 01/38] Add broker cache of coordinator dynamic configs --- .../CachingClusteredClientBenchmark.java | 4 +- .../movingaverage/MovingAverageQueryTest.java | 4 +- .../org/apache/druid/query/QueryContext.java | 8 ++ .../org/apache/druid/query/QueryContexts.java | 2 + .../druid/client/CachingClusteredClient.java | 18 +++- .../client/DynamicConfigurationManager.java | 83 +++++++++++++++++++ .../client/coordinator/CoordinatorClient.java | 5 ++ .../coordinator/CoordinatorClientImpl.java | 17 ++++ .../druid/client/selector/ServerSelector.java | 32 +++++++ .../DruidInternalDynamicConfigResource.java | 66 +++++++++++++++ ...chingClusteredClientFunctionalityTest.java | 4 +- .../CachingClusteredClientPerfTest.java | 3 +- .../client/CachingClusteredClientTest.java | 4 +- .../coordinator/NoopCoordinatorClient.java | 7 ++ ...yRunnerBasedOnClusteredClientTestBase.java | 4 +- .../TestDynamicConfigurationManager.java | 63 ++++++++++++++ .../java/org/apache/druid/cli/CliBroker.java | 4 + 17 files changed, 320 insertions(+), 8 deletions(-) create mode 100644 server/src/main/java/org/apache/druid/client/DynamicConfigurationManager.java create mode 100644 server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java create mode 100644 server/src/test/java/org/apache/druid/server/metrics/TestDynamicConfigurationManager.java diff --git a/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java b/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java index 58361aba7538..39718bb890b6 100644 --- a/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java +++ b/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java @@ -103,6 +103,7 @@ import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.coordination.ServerType; import org.apache.druid.server.metrics.NoopServiceEmitter; +import org.apache.druid.server.metrics.TestDynamicConfigurationManager; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.DataSegment.PruneSpecsHolder; import org.apache.druid.timeline.SegmentId; @@ -317,7 +318,8 @@ public boolean useParallelMergePool() }, forkJoinPool, QueryStackTests.DEFAULT_NOOP_SCHEDULER, - new NoopServiceEmitter() + new NoopServiceEmitter(), + new TestDynamicConfigurationManager() ); } diff --git a/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java b/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java index dd5f79eecf5d..031a2d09f45d 100644 --- a/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java +++ b/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java @@ -74,6 +74,7 @@ import org.apache.druid.server.initialization.ServerConfig; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.server.metrics.SubqueryCountStatsProvider; +import org.apache.druid.server.metrics.TestDynamicConfigurationManager; import org.apache.druid.testing.InitializedNullHandlingTest; import org.apache.druid.timeline.TimelineLookup; import org.apache.druid.utils.JvmUtils; @@ -365,7 +366,8 @@ public void registerServerRemovedCallback(Executor exec, ServerRemovedCallback c new BrokerParallelMergeConfig(), ForkJoinPool.commonPool(), QueryStackTests.DEFAULT_NOOP_SCHEDULER, - new NoopServiceEmitter() + new NoopServiceEmitter(), + new TestDynamicConfigurationManager() ); ClientQuerySegmentWalker walker = new ClientQuerySegmentWalker( diff --git a/processing/src/main/java/org/apache/druid/query/QueryContext.java b/processing/src/main/java/org/apache/druid/query/QueryContext.java index 5a1499c6c8b7..ca5c1cefaddc 100644 --- a/processing/src/main/java/org/apache/druid/query/QueryContext.java +++ b/processing/src/main/java/org/apache/druid/query/QueryContext.java @@ -552,6 +552,14 @@ public boolean getEnableJoinFilterRewriteValueColumnFilters() ); } + public boolean getQueryUnmanagedServers() + { + return getBoolean( + QueryContexts.QUERY_UNMANAGED_SERVERS, + QueryContexts.DEFAULT_QUERY_UNMANAGED_SERVERS + ); + } + public boolean getEnableRewriteJoinToFilter() { return getBoolean( diff --git a/processing/src/main/java/org/apache/druid/query/QueryContexts.java b/processing/src/main/java/org/apache/druid/query/QueryContexts.java index a2a81c6eb746..85e612359ac0 100644 --- a/processing/src/main/java/org/apache/druid/query/QueryContexts.java +++ b/processing/src/main/java/org/apache/druid/query/QueryContexts.java @@ -65,6 +65,7 @@ public class QueryContexts public static final String JOIN_FILTER_REWRITE_MAX_SIZE_KEY = "joinFilterRewriteMaxSize"; public static final String MAX_NUMERIC_IN_FILTERS = "maxNumericInFilters"; public static final String CURSOR_AUTO_ARRANGE_FILTERS = "cursorAutoArrangeFilters"; + public static final String QUERY_UNMANAGED_SERVERS = "queryUnmanagedServers"; // This flag controls whether a SQL join query with left scan should be attempted to be run as direct table access // instead of being wrapped inside a query. With direct table access enabled, Druid can push down the join operation to // data servers. @@ -149,6 +150,7 @@ public class QueryContexts public static final boolean DEFAULT_ENABLE_JOIN_FILTER_PUSH_DOWN = true; public static final boolean DEFAULT_ENABLE_JOIN_FILTER_REWRITE = true; public static final boolean DEFAULT_ENABLE_JOIN_FILTER_REWRITE_VALUE_COLUMN_FILTERS = false; + public static final boolean DEFAULT_QUERY_UNMANAGED_SERVERS = false; public static final boolean DEFAULT_ENABLE_REWRITE_JOIN_TO_FILTER = true; public static final long DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE = 10000; public static final boolean DEFAULT_ENABLE_SQL_JOIN_LEFT_SCAN_DIRECT = false; diff --git a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java index 5594f52af7b6..eefb95d99ea5 100644 --- a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java +++ b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java @@ -126,6 +126,7 @@ public class CachingClusteredClient implements QuerySegmentWalker private final ForkJoinPool pool; private final QueryScheduler scheduler; private final ServiceEmitter emitter; + private final DynamicConfigurationManager dynamicConfigurationManager; @Inject public CachingClusteredClient( @@ -139,7 +140,8 @@ public CachingClusteredClient( BrokerParallelMergeConfig parallelMergeConfig, @Merging ForkJoinPool pool, QueryScheduler scheduler, - ServiceEmitter emitter + ServiceEmitter emitter, + DynamicConfigurationManager dynamicConfigurationManager ) { this.conglomerate = conglomerate; @@ -153,6 +155,7 @@ public CachingClusteredClient( this.pool = pool; this.scheduler = scheduler; this.emitter = emitter; + this.dynamicConfigurationManager = dynamicConfigurationManager; if (cacheConfig.isQueryCacheable(Query.GROUP_BY) && (cacheConfig.isUseCache() || cacheConfig.isPopulateCache())) { log.warn( @@ -468,12 +471,23 @@ private Set computeSegmentsToQuery( } for (PartitionChunk chunk : filteredChunks) { ServerSelector server = chunk.getObject(); + + boolean queryUnmanagedServers = query.context().getQueryUnmanagedServers(); + Set serversToIgnore; + if (queryUnmanagedServers) { + // If this is a test query, ignore source servers. + serversToIgnore = dynamicConfigurationManager.getSourceClusterServers(); + } else { + serversToIgnore = dynamicConfigurationManager.getTargetCloneServers(); + } + + ServerSelector filteredServer = server.createFilteredServerSelector(o -> !serversToIgnore.contains(o)); final SegmentDescriptor segment = new SegmentDescriptor( holder.getInterval(), holder.getVersion(), chunk.getChunkNumber() ); - segments.add(new SegmentServerSelector(server, segment)); + segments.add(new SegmentServerSelector(filteredServer, segment)); } } return segments; diff --git a/server/src/main/java/org/apache/druid/client/DynamicConfigurationManager.java b/server/src/main/java/org/apache/druid/client/DynamicConfigurationManager.java new file mode 100644 index 000000000000..4ffc9ee966a3 --- /dev/null +++ b/server/src/main/java/org/apache/druid/client/DynamicConfigurationManager.java @@ -0,0 +1,83 @@ +/* + * 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.client; + +import com.google.inject.Inject; +import org.apache.druid.client.coordinator.CoordinatorClient; +import org.apache.druid.java.util.common.lifecycle.LifecycleStart; +import org.apache.druid.java.util.common.logger.Logger; +import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +public class DynamicConfigurationManager +{ + private static final Logger log = new Logger(DynamicConfigurationManager.class); + private final CoordinatorClient coordinatorClient; + + @Inject + public DynamicConfigurationManager(CoordinatorClient coordinatorClient) + { + this.coordinatorClient = coordinatorClient; + } + + private final AtomicReference config = new AtomicReference<>(); + + public CoordinatorDynamicConfig getConfig() + { + return config.get(); + } + + public Set getTargetCloneServers() + { + CoordinatorDynamicConfig coordinatorDynamicConfig = config.get(); + return coordinatorDynamicConfig.getCloneServers().keySet(); + } + + public Set getSourceClusterServers() + { + CoordinatorDynamicConfig coordinatorDynamicConfig = config.get(); + return new HashSet<>(coordinatorDynamicConfig.getCloneServers().values()); + } + + public void updateCloneServers(CoordinatorDynamicConfig updatedConfig) + { + config.set(updatedConfig); + } + + @LifecycleStart + public void start() throws InterruptedException + { + log.info("Initializing dynamic configuration."); + + try { + // TODO: handle exceptions and timeouts + CoordinatorDynamicConfig coordinatorDynamicConfig = coordinatorClient.getCoordinatorConfig().get(); + updateCloneServers(coordinatorDynamicConfig); + log.info("Synced clone servers TRUE [%s]", coordinatorDynamicConfig.getCloneServers()); + } + catch (Exception e) { + log.error(e, "Exception"); + throw new RuntimeException(e); + } + } +} diff --git a/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClient.java b/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClient.java index bcd3e4348e52..862be5c5b7c1 100644 --- a/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClient.java +++ b/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClient.java @@ -26,6 +26,7 @@ import org.apache.druid.rpc.ServiceRetryPolicy; import org.apache.druid.segment.metadata.DataSourceInformation; import org.apache.druid.server.compaction.CompactionStatusResponse; +import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import org.apache.druid.timeline.DataSegment; import org.joda.time.Interval; @@ -87,4 +88,8 @@ public interface CoordinatorClient */ ListenableFuture getCompactionSnapshots(@Nullable String dataSource); + /** + * TODO: javadoc + */ + ListenableFuture getCoordinatorConfig(); } diff --git a/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClientImpl.java b/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClientImpl.java index 50cd58e0eb33..42fba404fe69 100644 --- a/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClientImpl.java +++ b/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClientImpl.java @@ -38,6 +38,7 @@ import org.apache.druid.segment.metadata.DataSourceInformation; import org.apache.druid.server.compaction.CompactionStatusResponse; import org.apache.druid.server.coordination.LoadableDataSegment; +import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import org.apache.druid.timeline.DataSegment; import org.jboss.netty.handler.codec.http.HttpMethod; import org.joda.time.Interval; @@ -222,4 +223,20 @@ public ListenableFuture getCompactionSnapshots(@Nullab ) ); } + + @Override + public ListenableFuture getCoordinatorConfig() + { + return FutureUtils.transform( + client.asyncRequest( + new RequestBuilder(HttpMethod.GET, "/druid/coordinator/v1/config"), + new BytesFullResponseHandler() + ), + holder -> JacksonUtils.readValue( + jsonMapper, + holder.getContent(), + CoordinatorDynamicConfig.class + ) + ); + } } diff --git a/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java b/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java index 31793d1103ff..3c3cfa374ef7 100644 --- a/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java +++ b/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java @@ -36,6 +36,8 @@ import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; +import java.util.stream.Collectors; /** */ @@ -62,6 +64,36 @@ public ServerSelector( this.realtimeServers = new Int2ObjectRBTreeMap<>(strategy.getComparator()); } + private ServerSelector( + DataSegment segment, + TierSelectorStrategy strategy, + Int2ObjectRBTreeMap> historicalServers, + Int2ObjectRBTreeMap> realtimeServers + ) + { + this.segment = new AtomicReference<>(DataSegmentInterner.intern(segment)); + this.strategy = strategy; + this.historicalServers = historicalServers; + this.realtimeServers = realtimeServers; + } + + public ServerSelector createFilteredServerSelector(Predicate filter) + { + synchronized (this) { + Int2ObjectRBTreeMap> filteredHistoricals = new Int2ObjectRBTreeMap<>(); + for (int priority : historicalServers.keySet()) { + Set servers = historicalServers.get(priority); + filteredHistoricals.put(priority, + servers.stream() + .filter(server -> filter.test(server.getServer().getHost())) + .collect(Collectors.toSet()) + ); + } + + return new ServerSelector(segment.get(), strategy, filteredHistoricals, new Int2ObjectRBTreeMap<>(realtimeServers)); + } + } + public DataSegment getSegment() { return segment.get(); diff --git a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java new file mode 100644 index 000000000000..65539b4e0f91 --- /dev/null +++ b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java @@ -0,0 +1,66 @@ +/* + * 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.server; + +import com.google.inject.Inject; +import org.apache.druid.client.DynamicConfigurationManager; +import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; + +import javax.ws.rs.Consumes; +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.util.concurrent.atomic.AtomicReference; + +@Path("/druid-internal/v1/dynamicConfiguration") +public class DruidInternalDynamicConfigResource +{ + // TODO: Probably a better way + private final AtomicReference reference = + new AtomicReference<>(CoordinatorDynamicConfig.builder().build()); + private final DynamicConfigurationManager dynamicConfigurationManager; + + @Inject + public DruidInternalDynamicConfigResource(DynamicConfigurationManager dynamicConfigurationManager) + { + this.dynamicConfigurationManager = dynamicConfigurationManager; + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + @Path("/coordinatorDynamicConfig") + public Response getDatasource() + { + return Response.ok(reference.get()).build(); + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Path("/coordinatorDynamicConfig") + public Response getDatasource(final CoordinatorDynamicConfig.Builder dynamicConfigBuilder) + { + reference.set(dynamicConfigBuilder.build(reference.get())); + dynamicConfigurationManager.updateCloneServers(reference.get()); + return Response.ok().build(); + } +} diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java index 27fb1b49cc58..d822cdc63278 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java @@ -46,6 +46,7 @@ import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.coordination.ServerType; import org.apache.druid.server.metrics.NoopServiceEmitter; +import org.apache.druid.server.metrics.TestDynamicConfigurationManager; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.TimelineLookup; import org.apache.druid.timeline.VersionedIntervalTimeline; @@ -329,7 +330,8 @@ public int getDefaultMaxQueryParallelism() }, ForkJoinPool.commonPool(), QueryStackTests.DEFAULT_NOOP_SCHEDULER, - new NoopServiceEmitter() + new NoopServiceEmitter(), + new TestDynamicConfigurationManager() ); } diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java index d4611710e509..ff86d7480b7b 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java @@ -139,7 +139,8 @@ public void testGetQueryRunnerForSegments_singleIntervalLargeSegments() Mockito.mock(BrokerParallelMergeConfig.class), ForkJoinPool.commonPool(), queryScheduler, - new NoopServiceEmitter() + new NoopServiceEmitter(), + null ); Query fakeQuery = makeFakeQuery(interval); diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java index 8ea6e2e85cde..b16278b2702d 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java @@ -117,6 +117,7 @@ import org.apache.druid.server.coordination.ServerType; import org.apache.druid.server.initialization.ServerConfig; import org.apache.druid.server.metrics.NoopServiceEmitter; +import org.apache.druid.server.metrics.TestDynamicConfigurationManager; import org.apache.druid.server.scheduling.ManualQueryPrioritizationStrategy; import org.apache.druid.server.scheduling.NoQueryLaningStrategy; import org.apache.druid.timeline.DataSegment; @@ -2710,7 +2711,8 @@ public int getDefaultMaxQueryParallelism() NoQueryLaningStrategy.INSTANCE, new ServerConfig() ), - new NoopServiceEmitter() + new NoopServiceEmitter(), + new TestDynamicConfigurationManager() ); } diff --git a/server/src/test/java/org/apache/druid/client/coordinator/NoopCoordinatorClient.java b/server/src/test/java/org/apache/druid/client/coordinator/NoopCoordinatorClient.java index ac01db424afa..b8ec7d786726 100644 --- a/server/src/test/java/org/apache/druid/client/coordinator/NoopCoordinatorClient.java +++ b/server/src/test/java/org/apache/druid/client/coordinator/NoopCoordinatorClient.java @@ -26,6 +26,7 @@ import org.apache.druid.rpc.ServiceRetryPolicy; import org.apache.druid.segment.metadata.DataSourceInformation; import org.apache.druid.server.compaction.CompactionStatusResponse; +import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import org.apache.druid.timeline.DataSegment; import org.joda.time.Interval; @@ -90,4 +91,10 @@ public ListenableFuture getCompactionSnapshots(@Nullab throw new UnsupportedOperationException(); } + @Override + public ListenableFuture getCoordinatorConfig() + { + throw new UnsupportedOperationException(); + } + } diff --git a/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java b/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java index 76a63442e3ee..b06d0e3f6f9c 100644 --- a/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java +++ b/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java @@ -51,6 +51,7 @@ import org.apache.druid.segment.generator.SegmentGenerator; import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.metrics.NoopServiceEmitter; +import org.apache.druid.server.metrics.TestDynamicConfigurationManager; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.partition.NumberedShardSpec; import org.joda.time.Interval; @@ -132,7 +133,8 @@ public void setupTestBase() QueryStackTests.getParallelMergeConfig(USE_PARALLEL_MERGE_POOL_CONFIGURED), ForkJoinPool.commonPool(), QueryStackTests.DEFAULT_NOOP_SCHEDULER, - new NoopServiceEmitter() + new NoopServiceEmitter(), + new TestDynamicConfigurationManager() ); servers = new ArrayList<>(); } diff --git a/server/src/test/java/org/apache/druid/server/metrics/TestDynamicConfigurationManager.java b/server/src/test/java/org/apache/druid/server/metrics/TestDynamicConfigurationManager.java new file mode 100644 index 000000000000..c2034d6d56f7 --- /dev/null +++ b/server/src/test/java/org/apache/druid/server/metrics/TestDynamicConfigurationManager.java @@ -0,0 +1,63 @@ +/* + * 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.server.metrics; + +import com.google.common.collect.ImmutableSet; +import org.apache.druid.client.DynamicConfigurationManager; +import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; + +import java.util.Set; + +public class TestDynamicConfigurationManager extends DynamicConfigurationManager +{ + public TestDynamicConfigurationManager() + { + // TODO: finish and add tests. + super(null); + } + + @Override + public CoordinatorDynamicConfig getConfig() + { + return null; + } + + @Override + public Set getTargetCloneServers() + { + return ImmutableSet.of(); + } + + @Override + public Set getSourceClusterServers() + { + return ImmutableSet.of(); + } + + @Override + public void updateCloneServers(CoordinatorDynamicConfig updatedConfig) + { + } + + @Override + public void start() throws InterruptedException + { + } +} diff --git a/services/src/main/java/org/apache/druid/cli/CliBroker.java b/services/src/main/java/org/apache/druid/cli/CliBroker.java index 42bb7b51421c..2b0e57c5b7f4 100644 --- a/services/src/main/java/org/apache/druid/cli/CliBroker.java +++ b/services/src/main/java/org/apache/druid/cli/CliBroker.java @@ -29,6 +29,7 @@ import org.apache.druid.client.BrokerSegmentWatcherConfig; import org.apache.druid.client.BrokerServerView; import org.apache.druid.client.CachingClusteredClient; +import org.apache.druid.client.DynamicConfigurationManager; import org.apache.druid.client.DirectDruidClientFactory; import org.apache.druid.client.HttpServerInventoryViewResource; import org.apache.druid.client.InternalQueryConfig; @@ -59,6 +60,7 @@ import org.apache.druid.query.lookup.LookupModule; import org.apache.druid.server.BrokerQueryResource; import org.apache.druid.server.ClientInfoResource; +import org.apache.druid.server.DruidInternalDynamicConfigResource; import org.apache.druid.server.ClientQuerySegmentWalker; import org.apache.druid.server.ResponseContextConfig; import org.apache.druid.server.SegmentManager; @@ -160,6 +162,7 @@ protected List getModules() binder.bind(SubqueryCountStatsProvider.class).toInstance(new SubqueryCountStatsProvider()); Jerseys.addResource(binder, BrokerResource.class); Jerseys.addResource(binder, ClientInfoResource.class); + Jerseys.addResource(binder, DruidInternalDynamicConfigResource.class); LifecycleModule.register(binder, BrokerQueryResource.class); @@ -167,6 +170,7 @@ protected List getModules() LifecycleModule.register(binder, Server.class); binder.bind(SegmentManager.class).in(LazySingleton.class); + binder.bind(DynamicConfigurationManager.class).in(ManageLifecycle.class); binder.bind(ZkCoordinator.class).in(ManageLifecycle.class); binder.bind(ServerTypeConfig.class).toInstance(new ServerTypeConfig(ServerType.BROKER)); Jerseys.addResource(binder, HistoricalResource.class); From 267f13408270f25406a53c8d7e1bc23a17b05ef3 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Thu, 10 Apr 2025 14:59:42 +0530 Subject: [PATCH 02/38] Clean resource --- .../druid/client/selector/ServerSelector.java | 1 + .../server/DruidInternalDynamicConfigResource.java | 13 ++++--------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java b/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java index 3c3cfa374ef7..3e4edb4baf5c 100644 --- a/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java +++ b/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java @@ -36,6 +36,7 @@ import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; diff --git a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java index 65539b4e0f91..bc4dd52ddf00 100644 --- a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java +++ b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java @@ -30,14 +30,10 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.util.concurrent.atomic.AtomicReference; @Path("/druid-internal/v1/dynamicConfiguration") public class DruidInternalDynamicConfigResource { - // TODO: Probably a better way - private final AtomicReference reference = - new AtomicReference<>(CoordinatorDynamicConfig.builder().build()); private final DynamicConfigurationManager dynamicConfigurationManager; @Inject @@ -51,16 +47,15 @@ public DruidInternalDynamicConfigResource(DynamicConfigurationManager dynamicCon @Path("/coordinatorDynamicConfig") public Response getDatasource() { - return Response.ok(reference.get()).build(); + return Response.ok(dynamicConfigurationManager.getConfig()).build(); } @POST @Consumes(MediaType.APPLICATION_JSON) @Path("/coordinatorDynamicConfig") - public Response getDatasource(final CoordinatorDynamicConfig.Builder dynamicConfigBuilder) + public Response getDatasource(final CoordinatorDynamicConfig dynamicConfig) { - reference.set(dynamicConfigBuilder.build(reference.get())); - dynamicConfigurationManager.updateCloneServers(reference.get()); - return Response.ok().build(); + dynamicConfigurationManager.updateCloneServers(dynamicConfig); + return Response.ok(dynamicConfigurationManager.getConfig()).build(); } } From 9e48c6469d198a97496f6b90e1fb34b1cd7b61a6 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Thu, 10 Apr 2025 16:24:15 +0530 Subject: [PATCH 03/38] Refactor server selector --- .../druid/client/CachingClusteredClient.java | 46 ++++++++----- .../client/selector/HistoricalFilter.java | 39 +++++++++++ .../druid/client/selector/ServerSelector.java | 66 +++++++------------ ...ingClusteredClientCacheKeyManagerTest.java | 9 ++- 4 files changed, 101 insertions(+), 59 deletions(-) create mode 100644 server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java diff --git a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java index eefb95d99ea5..cce0962cb365 100644 --- a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java +++ b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java @@ -38,6 +38,7 @@ import org.apache.druid.client.cache.Cache; import org.apache.druid.client.cache.CacheConfig; import org.apache.druid.client.cache.CachePopulator; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.guice.annotations.Client; import org.apache.druid.guice.annotations.Merging; @@ -103,6 +104,7 @@ import java.util.TreeMap; import java.util.concurrent.ForkJoinPool; import java.util.function.BinaryOperator; +import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.stream.Collectors; @@ -294,7 +296,8 @@ private class SpecificQueryRunnable query, strategy, useCache, - populateCache + populateCache, + dynamicConfigurationManager ); } @@ -472,22 +475,12 @@ private Set computeSegmentsToQuery( for (PartitionChunk chunk : filteredChunks) { ServerSelector server = chunk.getObject(); - boolean queryUnmanagedServers = query.context().getQueryUnmanagedServers(); - Set serversToIgnore; - if (queryUnmanagedServers) { - // If this is a test query, ignore source servers. - serversToIgnore = dynamicConfigurationManager.getSourceClusterServers(); - } else { - serversToIgnore = dynamicConfigurationManager.getTargetCloneServers(); - } - - ServerSelector filteredServer = server.createFilteredServerSelector(o -> !serversToIgnore.contains(o)); final SegmentDescriptor segment = new SegmentDescriptor( holder.getInterval(), holder.getVersion(), chunk.getChunkNumber() ); - segments.add(new SegmentServerSelector(filteredServer, segment)); + segments.add(new SegmentServerSelector(server, segment)); } } return segments; @@ -612,7 +605,18 @@ private SortedMap> groupSegmentsByServer(Se { final SortedMap> serverSegments = new TreeMap<>(); for (SegmentServerSelector segmentServer : segments) { - final QueryableDruidServer queryableDruidServer = segmentServer.getServer().pick(query); + Supplier> supplier = () -> { + boolean queryUnmanagedServers = query.context().getQueryUnmanagedServers(); + if (queryUnmanagedServers) { + // If this is a test query, ignore source servers. + return dynamicConfigurationManager.getSourceClusterServers(); + } else { + return dynamicConfigurationManager.getTargetCloneServers(); + } + }; + + final QueryableDruidServer queryableDruidServer = segmentServer.getServer() + .pick(query, new HistoricalFilter(supplier)); if (queryableDruidServer == null) { log.makeAlert( @@ -791,17 +795,20 @@ static class CacheKeyManager private final Query query; private final CacheStrategy> strategy; private final boolean isSegmentLevelCachingEnable; + private final DynamicConfigurationManager dynamicConfigurationManager; CacheKeyManager( final Query query, final CacheStrategy> strategy, final boolean useCache, - final boolean populateCache + final boolean populateCache, + final DynamicConfigurationManager dynamicConfigurationManager ) { this.query = query; this.strategy = strategy; + this.dynamicConfigurationManager = dynamicConfigurationManager; this.isSegmentLevelCachingEnable = ((populateCache || useCache) && !query.context().isBySegment()); // explicit bySegment queries are never cached @@ -830,7 +837,16 @@ String computeResultLevelCachingEtag( Hasher hasher = Hashing.sha1().newHasher(); boolean hasOnlyHistoricalSegments = true; for (SegmentServerSelector p : segments) { - QueryableDruidServer queryableServer = p.getServer().pick(query); + Supplier> supplier = () -> { + boolean queryUnmanagedServers = query.context().getQueryUnmanagedServers(); + if (queryUnmanagedServers) { + // If this is a test query, ignore source servers. + return dynamicConfigurationManager.getSourceClusterServers(); + } else { + return dynamicConfigurationManager.getTargetCloneServers(); + } + }; + QueryableDruidServer queryableServer = p.getServer().pick(query, new HistoricalFilter(supplier)); if (queryableServer == null || !queryableServer.getServer().isSegmentReplicationTarget()) { hasOnlyHistoricalSegments = false; break; diff --git a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java new file mode 100644 index 000000000000..db263859a979 --- /dev/null +++ b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java @@ -0,0 +1,39 @@ +package org.apache.druid.client.selector; + +import com.google.common.collect.ImmutableSet; +import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap; +import org.apache.druid.client.QueryableDruidServer; + +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public class HistoricalFilter implements Function>, Int2ObjectRBTreeMap>> +{ + public static HistoricalFilter IDENTITIY_FILTER = new HistoricalFilter(ImmutableSet::of); + + public HistoricalFilter(Supplier> serversToIgnoreSupplier) + { + this.serversToIgnoreSupplier = serversToIgnoreSupplier; + } + + private final Supplier> serversToIgnoreSupplier; + + @Override + public Int2ObjectRBTreeMap> apply(Int2ObjectRBTreeMap> historicalServers) + { + final Set serversToIgnore = serversToIgnoreSupplier.get(); + final Int2ObjectRBTreeMap> filteredHistoricals = new Int2ObjectRBTreeMap<>(); + for (int priority : historicalServers.keySet()) { + Set servers = historicalServers.get(priority); + filteredHistoricals.put(priority, + servers.stream() + .filter(server -> !serversToIgnore.contains(server.getServer().getHost())) + .collect(Collectors.toSet()) + ); + } + + return filteredHistoricals; + } +} diff --git a/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java b/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java index 3e4edb4baf5c..61602dc7cfe6 100644 --- a/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java +++ b/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java @@ -36,9 +36,6 @@ import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; /** */ @@ -65,36 +62,6 @@ public ServerSelector( this.realtimeServers = new Int2ObjectRBTreeMap<>(strategy.getComparator()); } - private ServerSelector( - DataSegment segment, - TierSelectorStrategy strategy, - Int2ObjectRBTreeMap> historicalServers, - Int2ObjectRBTreeMap> realtimeServers - ) - { - this.segment = new AtomicReference<>(DataSegmentInterner.intern(segment)); - this.strategy = strategy; - this.historicalServers = historicalServers; - this.realtimeServers = realtimeServers; - } - - public ServerSelector createFilteredServerSelector(Predicate filter) - { - synchronized (this) { - Int2ObjectRBTreeMap> filteredHistoricals = new Int2ObjectRBTreeMap<>(); - for (int priority : historicalServers.keySet()) { - Set servers = historicalServers.get(priority); - filteredHistoricals.put(priority, - servers.stream() - .filter(server -> filter.test(server.getServer().getHost())) - .collect(Collectors.toSet()) - ); - } - - return new ServerSelector(segment.get(), strategy, filteredHistoricals, new Int2ObjectRBTreeMap<>(realtimeServers)); - } - } - public DataSegment getSegment() { return segment.get(); @@ -155,12 +122,17 @@ public boolean isEmpty() } public List getCandidates(final int numCandidates) + { + return getCandidates(numCandidates, HistoricalFilter.IDENTITIY_FILTER); + } + + public List getCandidates(final int numCandidates, HistoricalFilter filter) { List candidates; synchronized (this) { if (numCandidates > 0) { candidates = new ArrayList<>(numCandidates); - strategy.pick(historicalServers, segment.get(), numCandidates) + strategy.pick(filter.apply(historicalServers), segment.get(), numCandidates) .stream() .map(server -> server.getServer().getMetadata()) .forEach(candidates::add); @@ -173,21 +145,27 @@ public List getCandidates(final int numCandidates) } return candidates; } else { - return getAllServers(); + return getAllServers(filter); } } } public List getAllServers() + { + return getAllServers(HistoricalFilter.IDENTITIY_FILTER); + } + + public List getAllServers(HistoricalFilter filter) { final List servers = new ArrayList<>(); synchronized (this) { - historicalServers.values() - .stream() - .flatMap(Collection::stream) - .map(server -> server.getServer().getMetadata()) - .forEach(servers::add); + filter.apply(historicalServers) + .values() + .stream() + .flatMap(Collection::stream) + .map(server -> server.getServer().getMetadata()) + .forEach(servers::add); realtimeServers.values() .stream() @@ -201,10 +179,16 @@ public List getAllServers() @Nullable public QueryableDruidServer pick(@Nullable Query query) + { + return pick(query, HistoricalFilter.IDENTITIY_FILTER); + } + + @Nullable + public QueryableDruidServer pick(@Nullable Query query, HistoricalFilter filter) { synchronized (this) { if (!historicalServers.isEmpty()) { - return strategy.pick(query, historicalServers, segment.get()); + return strategy.pick(query, filter.apply(historicalServers), segment.get()); } return strategy.pick(query, realtimeServers, segment.get()); } diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java index 36e77dbaaec6..7139853752e5 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java @@ -200,7 +200,8 @@ public void testComputeEtag_noEffectIfUseAndPopulateFalse() query, strategy, false, - false + false, + null ); Set selectors = ImmutableSet.of( makeHistoricalServerSelector(1), @@ -259,7 +260,8 @@ public void testSegmentQueryCacheKey_useAndPopulateCacheFalse() query, strategy, false, - false + false, + null ).computeSegmentLevelQueryCacheKey()); } @@ -269,7 +271,8 @@ private CachingClusteredClient.CacheKeyManager makeKeyManager() query, strategy, true, - true + true, + null ); } From c449dc6420aa493019e7b633e1ec3dabf92028c7 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Fri, 11 Apr 2025 12:43:46 +0530 Subject: [PATCH 04/38] Make coordinator broadcast config changes --- .../DruidInternalDynamicConfigResource.java | 4 +- .../coordinator/CoordinatorDynamicConfig.java | 6 +- .../server/coordinator/DruidCoordinator.java | 31 +++- .../coordinator/duty/SyncBrokerDuty.java | 43 +++++ .../CoordinatorDynamicConfigsResource.java | 6 +- .../server/http/DynamicConfigSyncer.java | 149 ++++++++++++++++++ .../org/apache/druid/cli/CliCoordinator.java | 3 + 7 files changed, 236 insertions(+), 6 deletions(-) create mode 100644 server/src/main/java/org/apache/druid/server/coordinator/duty/SyncBrokerDuty.java create mode 100644 server/src/main/java/org/apache/druid/server/http/DynamicConfigSyncer.java diff --git a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java index bc4dd52ddf00..b4b0421d3ed0 100644 --- a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java +++ b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java @@ -53,9 +53,9 @@ public Response getDatasource() @POST @Consumes(MediaType.APPLICATION_JSON) @Path("/coordinatorDynamicConfig") - public Response getDatasource(final CoordinatorDynamicConfig dynamicConfig) + public Response setDatasource(final CoordinatorDynamicConfig dynamicConfig) { dynamicConfigurationManager.updateCloneServers(dynamicConfig); - return Response.ok(dynamicConfigurationManager.getConfig()).build(); + return Response.ok("OK").build(); } } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java b/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java index 8a219484acf1..dfb4d38a3b25 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java @@ -404,7 +404,8 @@ public boolean equals(Object o) that.dataSourcesToNotKillStalePendingSegmentsIn) && Objects.equals(decommissioningNodes, that.decommissioningNodes) && Objects.equals(turboLoadingNodes, that.turboLoadingNodes) - && Objects.equals(debugDimensions, that.debugDimensions); + && Objects.equals(debugDimensions, that.debugDimensions) + && Objects.equals(cloneServers, that.cloneServers); } @Override @@ -424,7 +425,8 @@ public int hashCode() decommissioningNodes, pauseCoordination, debugDimensions, - turboLoadingNodes + turboLoadingNodes, + cloneServers ); } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java b/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java index 8174d829df1c..14ef878888bb 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java @@ -83,6 +83,7 @@ import org.apache.druid.server.coordinator.duty.MetadataAction; import org.apache.druid.server.coordinator.duty.PrepareBalancerAndLoadQueues; import org.apache.druid.server.coordinator.duty.RunRules; +import org.apache.druid.server.coordinator.duty.SyncBrokerDuty; import org.apache.druid.server.coordinator.duty.UnloadUnusedSegments; import org.apache.druid.server.coordinator.loading.LoadQueuePeon; import org.apache.druid.server.coordinator.loading.LoadQueueTaskMaster; @@ -94,6 +95,7 @@ import org.apache.druid.server.coordinator.stats.Dimension; import org.apache.druid.server.coordinator.stats.RowKey; import org.apache.druid.server.coordinator.stats.Stats; +import org.apache.druid.server.http.DynamicConfigSyncer; import org.apache.druid.server.http.SegmentsToUpdateFilter; import org.apache.druid.server.lookup.cache.LookupCoordinatorManager; import org.apache.druid.timeline.DataSegment; @@ -142,6 +144,7 @@ public class DruidCoordinator @Nullable private final CoordinatorSegmentMetadataCache coordinatorSegmentMetadataCache; private final CentralizedDatasourceSchemaConfig centralizedDatasourceSchemaConfig; + private final DynamicConfigSyncer dynamicConfigSyncer; private volatile boolean started = false; @@ -169,7 +172,6 @@ public class DruidCoordinator private static final String INDEXING_SERVICE_DUTIES_DUTY_GROUP = "IndexingServiceDuties"; private static final String COMPACT_SEGMENTS_DUTIES_DUTY_GROUP = "CompactSegmentsDuties"; - @Inject public DruidCoordinator( DruidCoordinatorConfig config, MetadataManager metadataManager, @@ -188,6 +190,31 @@ public DruidCoordinator( CentralizedDatasourceSchemaConfig centralizedDatasourceSchemaConfig, CompactionStatusTracker compactionStatusTracker ) + { + this(config, metadataManager, serverInventoryView, emitter, scheduledExecutorFactory, overlordClient, taskMaster, loadQueueManager, serviceAnnouncer, self + , customDutyGroups, lookupCoordinatorManager, coordLeaderSelector, coordinatorSegmentMetadataCache, centralizedDatasourceSchemaConfig, compactionStatusTracker, null); + } + + @Inject + public DruidCoordinator( + DruidCoordinatorConfig config, + MetadataManager metadataManager, + ServerInventoryView serverInventoryView, + ServiceEmitter emitter, + ScheduledExecutorFactory scheduledExecutorFactory, + OverlordClient overlordClient, + LoadQueueTaskMaster taskMaster, + SegmentLoadQueueManager loadQueueManager, + ServiceAnnouncer serviceAnnouncer, + @Self DruidNode self, + CoordinatorCustomDutyGroups customDutyGroups, + LookupCoordinatorManager lookupCoordinatorManager, + @Coordinator DruidLeaderSelector coordLeaderSelector, + @Nullable CoordinatorSegmentMetadataCache coordinatorSegmentMetadataCache, + CentralizedDatasourceSchemaConfig centralizedDatasourceSchemaConfig, + CompactionStatusTracker compactionStatusTracker, + DynamicConfigSyncer dynamicConfigSyncer + ) { this.config = config; this.metadataManager = metadataManager; @@ -208,6 +235,7 @@ public DruidCoordinator( this.loadQueueManager = loadQueueManager; this.coordinatorSegmentMetadataCache = coordinatorSegmentMetadataCache; this.centralizedDatasourceSchemaConfig = centralizedDatasourceSchemaConfig; + this.dynamicConfigSyncer = dynamicConfigSyncer; this.compactSegments = initializeCompactSegmentsDuty(this.compactionStatusTracker); } @@ -560,6 +588,7 @@ private List makeHistoricalManagementDuties() new MarkEternityTombstonesAsUnused(deleteSegments), new BalanceSegments(config.getCoordinatorPeriod()), new CloneHistoricals(loadQueueManager), + new SyncBrokerDuty(dynamicConfigSyncer), new CollectLoadQueueStats() ); } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/duty/SyncBrokerDuty.java b/server/src/main/java/org/apache/druid/server/coordinator/duty/SyncBrokerDuty.java new file mode 100644 index 000000000000..83d7694348cd --- /dev/null +++ b/server/src/main/java/org/apache/druid/server/coordinator/duty/SyncBrokerDuty.java @@ -0,0 +1,43 @@ +/* + * 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.server.coordinator.duty; + +import org.apache.druid.server.coordinator.DruidCoordinatorRuntimeParams; +import org.apache.druid.server.http.DynamicConfigSyncer; + +import javax.annotation.Nullable; + +public class SyncBrokerDuty implements CoordinatorDuty +{ + private final DynamicConfigSyncer dynamicConfigSyncer; + + public SyncBrokerDuty(DynamicConfigSyncer dynamicConfigSyncer) + { + this.dynamicConfigSyncer = dynamicConfigSyncer; + } + + @Nullable + @Override + public DruidCoordinatorRuntimeParams run(DruidCoordinatorRuntimeParams params) + { + dynamicConfigSyncer.updateConfigIfNeeded(); + return params; + } +} diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java index 1dcbdb7e5f23..94882dca0df4 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java @@ -49,15 +49,18 @@ public class CoordinatorDynamicConfigsResource { private final CoordinatorConfigManager manager; private final AuditManager auditManager; + private final DynamicConfigSyncer dynamicConfigSyncer; @Inject public CoordinatorDynamicConfigsResource( CoordinatorConfigManager manager, - AuditManager auditManager + AuditManager auditManager, + DynamicConfigSyncer dynamicConfigSyncer ) { this.manager = manager; this.auditManager = auditManager; + this.dynamicConfigSyncer = dynamicConfigSyncer; } @GET @@ -84,6 +87,7 @@ public Response setDynamicConfigs( ); if (setResult.isOk()) { + dynamicConfigSyncer.updateConfigIfNeeded(); return Response.ok().build(); } else { return Response.status(Response.Status.BAD_REQUEST) diff --git a/server/src/main/java/org/apache/druid/server/http/DynamicConfigSyncer.java b/server/src/main/java/org/apache/druid/server/http/DynamicConfigSyncer.java new file mode 100644 index 000000000000..31f1685f21b8 --- /dev/null +++ b/server/src/main/java/org/apache/druid/server/http/DynamicConfigSyncer.java @@ -0,0 +1,149 @@ +/* + * 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.server.http; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableSet; +import com.google.inject.Inject; +import org.apache.druid.client.DruidServer; +import org.apache.druid.client.ServerInventoryView; +import org.apache.druid.guice.annotations.EscalatedGlobal; +import org.apache.druid.guice.annotations.Json; +import org.apache.druid.java.util.common.concurrent.Execs; +import org.apache.druid.java.util.common.logger.Logger; +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.FixedServiceLocator; +import org.apache.druid.rpc.RequestBuilder; +import org.apache.druid.rpc.ServiceClient; +import org.apache.druid.rpc.ServiceClientFactory; +import org.apache.druid.rpc.ServiceLocation; +import org.apache.druid.rpc.StandardRetryPolicy; +import org.apache.druid.server.coordination.DruidServerMetadata; +import org.apache.druid.server.coordination.ServerType; +import org.apache.druid.server.coordinator.CoordinatorConfigManager; +import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; +import org.jboss.netty.handler.codec.http.HttpMethod; +import org.jboss.netty.handler.codec.http.HttpResponseStatus; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +import static org.apache.druid.discovery.NodeRole.BROKER; + +public class DynamicConfigSyncer +{ + private static final Logger log = new Logger(DynamicConfigSyncer.class); + protected final ExecutorService exec; + private final ServiceClientFactory clientFactory; + private final CoordinatorConfigManager configManager; + private final List inSyncBrokers; + private final ObjectMapper objectMapper; + private final ServerInventoryView serverInventoryView; + private final AtomicReference lastKnownConfig = new AtomicReference<>(); + + @Inject + public DynamicConfigSyncer( + @EscalatedGlobal final ServiceClientFactory clientFactory, + CoordinatorConfigManager configManager, + @Json ObjectMapper objectMapper, + ServerInventoryView serverInventoryView + ) + { + this.clientFactory = clientFactory; + this.configManager = configManager; + this.objectMapper = objectMapper; + this.serverInventoryView = serverInventoryView; + this.exec = Execs.singleThreaded("DynamicConfigSyncer-%d"); + this.inSyncBrokers = new ArrayList<>(); + } + + private void updateBroker(DruidServerMetadata broker) + { + ServiceLocation serviceLocation = ServiceLocation.fromDruidServerMetadata(broker); + ServiceClient serviceClient = clientFactory.makeClient( + BROKER.getJsonName(), + new FixedServiceLocator(serviceLocation), + StandardRetryPolicy.builder().maxAttempts(6).build() + ); + + try { + RequestBuilder requestBuilder = + new RequestBuilder(HttpMethod.POST, "/druid-internal/v1/dynamicConfiguration/coordinatorDynamicConfig") + .jsonContent(objectMapper, configManager.getCurrentDynamicConfig()); + + BytesFullResponseHolder request = serviceClient.request( + requestBuilder, + new BytesFullResponseHandler() + ); + HttpResponseStatus status = request.getStatus(); + if (status.equals(HttpResponseStatus.OK)) { + log.info("Successfully posted dynamic configs to [%s]", broker.getHost()); + inSyncBrokers.add(broker.getHost()); + log.info("In sync: [%s]", inSyncBrokers); + } else { + log.error("Error [%s] while posting dynamic configs to [%s]", status.getCode(), broker.getHostAndPort()); + } + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void updateConfigIfNeeded() + { + log.info("Running Broker sync duty"); + CoordinatorDynamicConfig currentDynamicConfig = configManager.getCurrentDynamicConfig(); + if (currentDynamicConfig.equals(lastKnownConfig.get())) { + log.info("No need to change, already latest"); + } else { + lastKnownConfig.set(currentDynamicConfig); + inSyncBrokers.clear(); + getCurrentBrokers().forEach(broker -> exec.submit(() -> updateBroker(broker))); + } + } + + public Set getCurrentBrokers() + { + // TODO: work around + Set collect = serverInventoryView + .getInventory() + .stream() + .filter(ds -> ServerType.BROKER.equals(ds.getType())) + .map(DruidServer::getMetadata) + .collect(Collectors.toSet()); + log.info("SERVER VIEW BROKERS: [%s]", collect); + return ImmutableSet.of( + new DruidServerMetadata( + "localhost:8082", + "localhost:8082", + null, 0, ServerType.BROKER, "tier1", 0) + ); + } + + public List getInSyncBrokers() + { + return inSyncBrokers; + } +} diff --git a/services/src/main/java/org/apache/druid/cli/CliCoordinator.java b/services/src/main/java/org/apache/druid/cli/CliCoordinator.java index 1f61d9716eba..3e3664b02979 100644 --- a/services/src/main/java/org/apache/druid/cli/CliCoordinator.java +++ b/services/src/main/java/org/apache/druid/cli/CliCoordinator.java @@ -38,6 +38,7 @@ import org.apache.druid.client.CoordinatorSegmentWatcherConfig; import org.apache.druid.client.CoordinatorServerView; import org.apache.druid.client.DirectDruidClientFactory; +import org.apache.druid.client.DynamicConfigurationManager; import org.apache.druid.client.HttpServerInventoryViewResource; import org.apache.druid.client.InternalQueryConfig; import org.apache.druid.client.coordinator.Coordinator; @@ -116,6 +117,7 @@ import org.apache.druid.server.http.CoordinatorRedirectInfo; import org.apache.druid.server.http.CoordinatorResource; import org.apache.druid.server.http.DataSourcesResource; +import org.apache.druid.server.http.DynamicConfigSyncer; import org.apache.druid.server.http.IntervalsResource; import org.apache.druid.server.http.LookupCoordinatorResource; import org.apache.druid.server.http.MetadataResource; @@ -224,6 +226,7 @@ public void configure(Binder binder) binder.bind(DruidCoordinatorConfig.class); binder.bind(RedirectFilter.class).in(LazySingleton.class); + binder.bind(DynamicConfigSyncer.class).in(LazySingleton.class); if (beOverlord) { binder.bind(RedirectInfo.class).to(CoordinatorOverlordRedirectInfo.class).in(LazySingleton.class); } else { From b5713d142e8f96baa8616ffa52c9e7aa1892a95c Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Fri, 11 Apr 2025 14:43:54 +0530 Subject: [PATCH 05/38] Add status APIs --- .../server/coordinator/CloneDetails.java | 41 +++++++++++++ .../coordinator/CloneStatusManager.java | 59 +++++++++++++++++++ .../server/coordinator/DruidCoordinator.java | 9 ++- .../coordinator/duty/CloneHistoricals.java | 28 +++++---- .../server/http/CoordinatorResource.java | 30 +++++++++- .../CoordinatorSimulationBuilder.java | 4 +- .../org/apache/druid/cli/CliCoordinator.java | 2 + 7 files changed, 157 insertions(+), 16 deletions(-) create mode 100644 server/src/main/java/org/apache/druid/server/coordinator/CloneDetails.java create mode 100644 server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneDetails.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneDetails.java new file mode 100644 index 000000000000..7ac5c4afde6a --- /dev/null +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneDetails.java @@ -0,0 +1,41 @@ +package org.apache.druid.server.coordinator; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class CloneDetails +{ + final String sourceServer; + final long segmentsRemaining; + final long bytesRemaining; + + @JsonCreator + public CloneDetails(@JsonProperty String sourceServer, @JsonProperty long segmentsRemaining, @JsonProperty long bytesRemaining) + { + this.sourceServer = sourceServer; + this.segmentsRemaining = segmentsRemaining; + this.bytesRemaining = bytesRemaining; + } + + @JsonProperty + public String getSourceServer() + { + return sourceServer; + } + + @JsonProperty + public long getSegmentsRemaining() + { + return segmentsRemaining; + } + + @JsonProperty + public long getBytesRemaining() + { + return bytesRemaining; + } + + public enum Status { + CLONING + } +} diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java new file mode 100644 index 000000000000..cac271bd6707 --- /dev/null +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java @@ -0,0 +1,59 @@ +package org.apache.druid.server.coordinator; + +import com.google.errorprone.annotations.concurrent.GuardedBy; +import org.apache.druid.java.util.common.logger.Logger; +import org.apache.druid.server.coordinator.loading.SegmentAction; +import org.apache.druid.timeline.DataSegment; + +import java.util.HashMap; +import java.util.Map; + +public class CloneStatusManager +{ + private static final Logger log = new Logger(CloneStatusManager.class); + @GuardedBy("this") + private final Map cloneStatusMap; + + public CloneStatusManager() { + cloneStatusMap = new HashMap<>(); + } + + public Map getCloneStatusMap() + { + synchronized (this) { + return cloneStatusMap; + } + } + + public void updateStats(Map historicalMap, Map cloneServers) + { + synchronized (this) { + cloneStatusMap.clear(); + + for (Map.Entry entry : cloneServers.entrySet()) { + String targetServerName = entry.getKey(); + ServerHolder targetServer = historicalMap.get(entry.getKey()); + String sourceServerName = entry.getValue(); + ServerHolder sourceServer = historicalMap.get(entry.getValue()); + + int segmentsLeft = 0; + long bytesLeft = 0; + + if (targetServer == null) { + cloneStatusMap.put(targetServerName, new CloneDetails(sourceServerName, 0, 0)); + continue; + } + + for (Map.Entry queuedSegment: targetServer.getQueuedSegments().entrySet()) { + if (queuedSegment.getValue().isLoad()) { + segmentsLeft++; + bytesLeft += queuedSegment.getKey().getSize(); + } + } + + cloneStatusMap.put(targetServerName, new CloneDetails(sourceServerName, segmentsLeft, bytesLeft)); + } + } + } +} + diff --git a/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java b/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java index 14ef878888bb..30b6c4e63a3c 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java @@ -145,6 +145,7 @@ public class DruidCoordinator private final CoordinatorSegmentMetadataCache coordinatorSegmentMetadataCache; private final CentralizedDatasourceSchemaConfig centralizedDatasourceSchemaConfig; private final DynamicConfigSyncer dynamicConfigSyncer; + private final CloneStatusManager cloneStatusManager; private volatile boolean started = false; @@ -192,7 +193,7 @@ public DruidCoordinator( ) { this(config, metadataManager, serverInventoryView, emitter, scheduledExecutorFactory, overlordClient, taskMaster, loadQueueManager, serviceAnnouncer, self - , customDutyGroups, lookupCoordinatorManager, coordLeaderSelector, coordinatorSegmentMetadataCache, centralizedDatasourceSchemaConfig, compactionStatusTracker, null); + , customDutyGroups, lookupCoordinatorManager, coordLeaderSelector, coordinatorSegmentMetadataCache, centralizedDatasourceSchemaConfig, compactionStatusTracker, null, null); } @Inject @@ -213,7 +214,8 @@ public DruidCoordinator( @Nullable CoordinatorSegmentMetadataCache coordinatorSegmentMetadataCache, CentralizedDatasourceSchemaConfig centralizedDatasourceSchemaConfig, CompactionStatusTracker compactionStatusTracker, - DynamicConfigSyncer dynamicConfigSyncer + DynamicConfigSyncer dynamicConfigSyncer, + CloneStatusManager cloneStatusManager ) { this.config = config; @@ -236,6 +238,7 @@ public DruidCoordinator( this.coordinatorSegmentMetadataCache = coordinatorSegmentMetadataCache; this.centralizedDatasourceSchemaConfig = centralizedDatasourceSchemaConfig; this.dynamicConfigSyncer = dynamicConfigSyncer; + this.cloneStatusManager = cloneStatusManager; this.compactSegments = initializeCompactSegmentsDuty(this.compactionStatusTracker); } @@ -587,7 +590,7 @@ private List makeHistoricalManagementDuties() new MarkOvershadowedSegmentsAsUnused(deleteSegments), new MarkEternityTombstonesAsUnused(deleteSegments), new BalanceSegments(config.getCoordinatorPeriod()), - new CloneHistoricals(loadQueueManager), + new CloneHistoricals(loadQueueManager, cloneStatusManager), new SyncBrokerDuty(dynamicConfigSyncer), new CollectLoadQueueStats() ); diff --git a/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java b/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java index 25534f1ddfbd..0e3ca83ba226 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java @@ -20,7 +20,9 @@ package org.apache.druid.server.coordinator.duty; import org.apache.druid.java.util.common.logger.Logger; +import org.apache.druid.server.coordinator.CloneStatusManager; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; +import org.apache.druid.server.coordinator.DruidCluster; import org.apache.druid.server.coordinator.DruidCoordinatorRuntimeParams; import org.apache.druid.server.coordinator.ServerHolder; import org.apache.druid.server.coordinator.loading.SegmentAction; @@ -45,10 +47,12 @@ public class CloneHistoricals implements CoordinatorDuty { private static final Logger log = new Logger(CloneHistoricals.class); private final SegmentLoadQueueManager loadQueueManager; + private final CloneStatusManager cloneStatusManager; - public CloneHistoricals(SegmentLoadQueueManager loadQueueManager) + public CloneHistoricals(SegmentLoadQueueManager loadQueueManager, CloneStatusManager cloneStatusManager) { this.loadQueueManager = loadQueueManager; + this.cloneStatusManager = cloneStatusManager; } @Override @@ -56,6 +60,7 @@ public DruidCoordinatorRuntimeParams run(DruidCoordinatorRuntimeParams params) { final Map cloneServers = params.getCoordinatorDynamicConfig().getCloneServers(); final CoordinatorRunStats stats = params.getCoordinatorStats(); + final DruidCluster cluster = params.getDruidCluster(); if (cloneServers.isEmpty()) { // No servers to be cloned. @@ -63,15 +68,14 @@ public DruidCoordinatorRuntimeParams run(DruidCoordinatorRuntimeParams params) } // Create a map of host to historical. - final Map historicalMap = params.getDruidCluster() - .getHistoricals() - .values() - .stream() - .flatMap(Collection::stream) - .collect(Collectors.toMap( - serverHolder -> serverHolder.getServer().getHost(), - serverHolder -> serverHolder - )); + final Map historicalMap = cluster.getHistoricals() + .values() + .stream() + .flatMap(Collection::stream) + .collect(Collectors.toMap( + serverHolder -> serverHolder.getServer().getHost(), + serverHolder -> serverHolder + )); for (Map.Entry entry : cloneServers.entrySet()) { final String targetHistoricalName = entry.getKey(); @@ -84,7 +88,7 @@ public DruidCoordinatorRuntimeParams run(DruidCoordinatorRuntimeParams params) log.error( "Could not process clone mapping[%s] as historical[%s] does not exist.", entry, - (sourceServer == null ? sourceHistoricalName : targetHistoricalName) + (targetServer == null ? sourceHistoricalName : targetHistoricalName) ); continue; } @@ -114,6 +118,8 @@ public DruidCoordinatorRuntimeParams run(DruidCoordinatorRuntimeParams params) } } + cloneStatusManager.updateStats(historicalMap, cloneServers); + return params; } } diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java index 1f61464bafbf..37b68cbc2079 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java @@ -24,6 +24,7 @@ import com.google.common.collect.Maps; import com.google.inject.Inject; import com.sun.jersey.spi.container.ResourceFilters; +import org.apache.druid.server.coordinator.CloneStatusManager; import org.apache.druid.server.coordinator.DruidCoordinator; import org.apache.druid.server.http.security.StateResourceFilter; import org.apache.druid.timeline.DataSegment; @@ -43,11 +44,22 @@ public class CoordinatorResource { private final DruidCoordinator coordinator; + private final CloneStatusManager cloneStatusManager; + private final DynamicConfigSyncer dynamicConfigSyncer; - @Inject public CoordinatorResource(DruidCoordinator coordinator) { this.coordinator = coordinator; + this.cloneStatusManager = null; + dynamicConfigSyncer = null; + } + + @Inject + public CoordinatorResource(DruidCoordinator coordinator, CloneStatusManager cloneStatusManager, DynamicConfigSyncer dynamicConfigSyncer) + { + this.coordinator = coordinator; + this.cloneStatusManager = cloneStatusManager; + this.dynamicConfigSyncer = dynamicConfigSyncer; } @GET @@ -158,4 +170,20 @@ public Response getStatusOfDuties() { return Response.ok(new CoordinatorDutyStatus(coordinator.getStatusOfDuties())).build(); } + + @GET + @Path("/brokerConfigurationStatus") + @Produces(MediaType.APPLICATION_JSON) + public Response getBrokerStatus() + { + return Response.ok(dynamicConfigSyncer.getInSyncBrokers()).build(); + } + + @GET + @Path("/cloneStatus") + @Produces(MediaType.APPLICATION_JSON) + public Response getCloneStatus() + { + return Response.ok(cloneStatusManager.getCloneStatusMap()).build(); + } } diff --git a/server/src/test/java/org/apache/druid/server/coordinator/simulate/CoordinatorSimulationBuilder.java b/server/src/test/java/org/apache/druid/server/coordinator/simulate/CoordinatorSimulationBuilder.java index ffceedb21f94..f8e28e4979bc 100644 --- a/server/src/test/java/org/apache/druid/server/coordinator/simulate/CoordinatorSimulationBuilder.java +++ b/server/src/test/java/org/apache/druid/server/coordinator/simulate/CoordinatorSimulationBuilder.java @@ -220,7 +220,9 @@ public CoordinatorSimulation build() env.leaderSelector, null, CentralizedDatasourceSchemaConfig.create(), - new CompactionStatusTracker(OBJECT_MAPPER) + new CompactionStatusTracker(OBJECT_MAPPER), + null, + null ); return new SimulationImpl(coordinator, env); diff --git a/services/src/main/java/org/apache/druid/cli/CliCoordinator.java b/services/src/main/java/org/apache/druid/cli/CliCoordinator.java index 3e3664b02979..85d5acf286b5 100644 --- a/services/src/main/java/org/apache/druid/cli/CliCoordinator.java +++ b/services/src/main/java/org/apache/druid/cli/CliCoordinator.java @@ -97,6 +97,7 @@ import org.apache.druid.server.QueryScheduler; import org.apache.druid.server.QuerySchedulerProvider; import org.apache.druid.server.compaction.CompactionStatusTracker; +import org.apache.druid.server.coordinator.CloneStatusManager; import org.apache.druid.server.coordinator.CoordinatorConfigManager; import org.apache.druid.server.coordinator.DruidCoordinator; import org.apache.druid.server.coordinator.MetadataManager; @@ -249,6 +250,7 @@ public void configure(Binder binder) .in(ManageLifecycle.class); binder.bind(LookupCoordinatorManager.class).in(LazySingleton.class); + binder.bind(CloneStatusManager.class).in(LazySingleton.class); binder.bind(CoordinatorConfigManager.class); binder.bind(MetadataManager.class); From aaa39e58d2058006b7c72376a0cc01d03508741b Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Fri, 11 Apr 2025 15:15:56 +0530 Subject: [PATCH 06/38] rename to CoordinatorDynamicConfigView --- .../CachingClusteredClientBenchmark.java | 3 +- .../movingaverage/MovingAverageQueryTest.java | 3 +- .../druid/client/CachingClusteredClient.java | 22 +++---- ...java => CoordinatorDynamicConfigView.java} | 8 +-- .../client/coordinator/CoordinatorClient.java | 2 +- .../coordinator/CoordinatorClientImpl.java | 2 +- .../DruidInternalDynamicConfigResource.java | 12 ++-- ...chingClusteredClientFunctionalityTest.java | 3 +- .../client/CachingClusteredClientTest.java | 3 +- .../coordinator/NoopCoordinatorClient.java | 2 +- ...yRunnerBasedOnClusteredClientTestBase.java | 3 +- .../TestDynamicConfigurationManager.java | 63 ------------------- .../java/org/apache/druid/cli/CliBroker.java | 4 +- .../org/apache/druid/cli/CliCoordinator.java | 1 - 14 files changed, 31 insertions(+), 100 deletions(-) rename server/src/main/java/org/apache/druid/client/{DynamicConfigurationManager.java => CoordinatorDynamicConfigView.java} (91%) delete mode 100644 server/src/test/java/org/apache/druid/server/metrics/TestDynamicConfigurationManager.java diff --git a/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java b/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java index 39718bb890b6..030441aee937 100644 --- a/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java +++ b/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java @@ -103,7 +103,6 @@ import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.coordination.ServerType; import org.apache.druid.server.metrics.NoopServiceEmitter; -import org.apache.druid.server.metrics.TestDynamicConfigurationManager; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.DataSegment.PruneSpecsHolder; import org.apache.druid.timeline.SegmentId; @@ -319,7 +318,7 @@ public boolean useParallelMergePool() forkJoinPool, QueryStackTests.DEFAULT_NOOP_SCHEDULER, new NoopServiceEmitter(), - new TestDynamicConfigurationManager() + null ); } diff --git a/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java b/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java index 031a2d09f45d..c00d996291da 100644 --- a/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java +++ b/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java @@ -74,7 +74,6 @@ import org.apache.druid.server.initialization.ServerConfig; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.server.metrics.SubqueryCountStatsProvider; -import org.apache.druid.server.metrics.TestDynamicConfigurationManager; import org.apache.druid.testing.InitializedNullHandlingTest; import org.apache.druid.timeline.TimelineLookup; import org.apache.druid.utils.JvmUtils; @@ -367,7 +366,7 @@ public void registerServerRemovedCallback(Executor exec, ServerRemovedCallback c ForkJoinPool.commonPool(), QueryStackTests.DEFAULT_NOOP_SCHEDULER, new NoopServiceEmitter(), - new TestDynamicConfigurationManager() + null ); ClientQuerySegmentWalker walker = new ClientQuerySegmentWalker( diff --git a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java index cce0962cb365..59d37fbeade5 100644 --- a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java +++ b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java @@ -128,7 +128,7 @@ public class CachingClusteredClient implements QuerySegmentWalker private final ForkJoinPool pool; private final QueryScheduler scheduler; private final ServiceEmitter emitter; - private final DynamicConfigurationManager dynamicConfigurationManager; + private final CoordinatorDynamicConfigView coordinatorDynamicConfigView; @Inject public CachingClusteredClient( @@ -143,7 +143,7 @@ public CachingClusteredClient( @Merging ForkJoinPool pool, QueryScheduler scheduler, ServiceEmitter emitter, - DynamicConfigurationManager dynamicConfigurationManager + CoordinatorDynamicConfigView coordinatorDynamicConfigView ) { this.conglomerate = conglomerate; @@ -157,7 +157,7 @@ public CachingClusteredClient( this.pool = pool; this.scheduler = scheduler; this.emitter = emitter; - this.dynamicConfigurationManager = dynamicConfigurationManager; + this.coordinatorDynamicConfigView = coordinatorDynamicConfigView; if (cacheConfig.isQueryCacheable(Query.GROUP_BY) && (cacheConfig.isUseCache() || cacheConfig.isPopulateCache())) { log.warn( @@ -297,7 +297,7 @@ private class SpecificQueryRunnable strategy, useCache, populateCache, - dynamicConfigurationManager + coordinatorDynamicConfigView ); } @@ -609,9 +609,9 @@ private SortedMap> groupSegmentsByServer(Se boolean queryUnmanagedServers = query.context().getQueryUnmanagedServers(); if (queryUnmanagedServers) { // If this is a test query, ignore source servers. - return dynamicConfigurationManager.getSourceClusterServers(); + return coordinatorDynamicConfigView.getSourceClusterServers(); } else { - return dynamicConfigurationManager.getTargetCloneServers(); + return coordinatorDynamicConfigView.getTargetCloneServers(); } }; @@ -795,20 +795,20 @@ static class CacheKeyManager private final Query query; private final CacheStrategy> strategy; private final boolean isSegmentLevelCachingEnable; - private final DynamicConfigurationManager dynamicConfigurationManager; + private final CoordinatorDynamicConfigView coordinatorDynamicConfigView; CacheKeyManager( final Query query, final CacheStrategy> strategy, final boolean useCache, final boolean populateCache, - final DynamicConfigurationManager dynamicConfigurationManager + final CoordinatorDynamicConfigView coordinatorDynamicConfigView ) { this.query = query; this.strategy = strategy; - this.dynamicConfigurationManager = dynamicConfigurationManager; + this.coordinatorDynamicConfigView = coordinatorDynamicConfigView; this.isSegmentLevelCachingEnable = ((populateCache || useCache) && !query.context().isBySegment()); // explicit bySegment queries are never cached @@ -841,9 +841,9 @@ String computeResultLevelCachingEtag( boolean queryUnmanagedServers = query.context().getQueryUnmanagedServers(); if (queryUnmanagedServers) { // If this is a test query, ignore source servers. - return dynamicConfigurationManager.getSourceClusterServers(); + return coordinatorDynamicConfigView.getSourceClusterServers(); } else { - return dynamicConfigurationManager.getTargetCloneServers(); + return coordinatorDynamicConfigView.getTargetCloneServers(); } }; QueryableDruidServer queryableServer = p.getServer().pick(query, new HistoricalFilter(supplier)); diff --git a/server/src/main/java/org/apache/druid/client/DynamicConfigurationManager.java b/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java similarity index 91% rename from server/src/main/java/org/apache/druid/client/DynamicConfigurationManager.java rename to server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java index 4ffc9ee966a3..9d8cbfc99742 100644 --- a/server/src/main/java/org/apache/druid/client/DynamicConfigurationManager.java +++ b/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java @@ -29,13 +29,13 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicReference; -public class DynamicConfigurationManager +public class CoordinatorDynamicConfigView { - private static final Logger log = new Logger(DynamicConfigurationManager.class); + private static final Logger log = new Logger(CoordinatorDynamicConfigView.class); private final CoordinatorClient coordinatorClient; @Inject - public DynamicConfigurationManager(CoordinatorClient coordinatorClient) + public CoordinatorDynamicConfigView(CoordinatorClient coordinatorClient) { this.coordinatorClient = coordinatorClient; } @@ -71,7 +71,7 @@ public void start() throws InterruptedException try { // TODO: handle exceptions and timeouts - CoordinatorDynamicConfig coordinatorDynamicConfig = coordinatorClient.getCoordinatorConfig().get(); + CoordinatorDynamicConfig coordinatorDynamicConfig = coordinatorClient.getCoordinatorDynamicConfig().get(); updateCloneServers(coordinatorDynamicConfig); log.info("Synced clone servers TRUE [%s]", coordinatorDynamicConfig.getCloneServers()); } diff --git a/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClient.java b/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClient.java index 862be5c5b7c1..8b3ce2d0a76d 100644 --- a/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClient.java +++ b/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClient.java @@ -91,5 +91,5 @@ public interface CoordinatorClient /** * TODO: javadoc */ - ListenableFuture getCoordinatorConfig(); + ListenableFuture getCoordinatorDynamicConfig(); } diff --git a/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClientImpl.java b/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClientImpl.java index 42fba404fe69..bb89bc965e8c 100644 --- a/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClientImpl.java +++ b/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClientImpl.java @@ -225,7 +225,7 @@ public ListenableFuture getCompactionSnapshots(@Nullab } @Override - public ListenableFuture getCoordinatorConfig() + public ListenableFuture getCoordinatorDynamicConfig() { return FutureUtils.transform( client.asyncRequest( diff --git a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java index b4b0421d3ed0..a6e8c104d8de 100644 --- a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java +++ b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java @@ -20,7 +20,7 @@ package org.apache.druid.server; import com.google.inject.Inject; -import org.apache.druid.client.DynamicConfigurationManager; +import org.apache.druid.client.CoordinatorDynamicConfigView; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import javax.ws.rs.Consumes; @@ -34,12 +34,12 @@ @Path("/druid-internal/v1/dynamicConfiguration") public class DruidInternalDynamicConfigResource { - private final DynamicConfigurationManager dynamicConfigurationManager; + private final CoordinatorDynamicConfigView coordinatorDynamicConfigView; @Inject - public DruidInternalDynamicConfigResource(DynamicConfigurationManager dynamicConfigurationManager) + public DruidInternalDynamicConfigResource(CoordinatorDynamicConfigView coordinatorDynamicConfigView) { - this.dynamicConfigurationManager = dynamicConfigurationManager; + this.coordinatorDynamicConfigView = coordinatorDynamicConfigView; } @GET @@ -47,7 +47,7 @@ public DruidInternalDynamicConfigResource(DynamicConfigurationManager dynamicCon @Path("/coordinatorDynamicConfig") public Response getDatasource() { - return Response.ok(dynamicConfigurationManager.getConfig()).build(); + return Response.ok(coordinatorDynamicConfigView.getConfig()).build(); } @POST @@ -55,7 +55,7 @@ public Response getDatasource() @Path("/coordinatorDynamicConfig") public Response setDatasource(final CoordinatorDynamicConfig dynamicConfig) { - dynamicConfigurationManager.updateCloneServers(dynamicConfig); + coordinatorDynamicConfigView.updateCloneServers(dynamicConfig); return Response.ok("OK").build(); } } diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java index d822cdc63278..cd2a5b895383 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java @@ -46,7 +46,6 @@ import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.coordination.ServerType; import org.apache.druid.server.metrics.NoopServiceEmitter; -import org.apache.druid.server.metrics.TestDynamicConfigurationManager; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.TimelineLookup; import org.apache.druid.timeline.VersionedIntervalTimeline; @@ -331,7 +330,7 @@ public int getDefaultMaxQueryParallelism() ForkJoinPool.commonPool(), QueryStackTests.DEFAULT_NOOP_SCHEDULER, new NoopServiceEmitter(), - new TestDynamicConfigurationManager() + null ); } diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java index b16278b2702d..c7943bc70a96 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java @@ -117,7 +117,6 @@ import org.apache.druid.server.coordination.ServerType; import org.apache.druid.server.initialization.ServerConfig; import org.apache.druid.server.metrics.NoopServiceEmitter; -import org.apache.druid.server.metrics.TestDynamicConfigurationManager; import org.apache.druid.server.scheduling.ManualQueryPrioritizationStrategy; import org.apache.druid.server.scheduling.NoQueryLaningStrategy; import org.apache.druid.timeline.DataSegment; @@ -2712,7 +2711,7 @@ public int getDefaultMaxQueryParallelism() new ServerConfig() ), new NoopServiceEmitter(), - new TestDynamicConfigurationManager() + null ); } diff --git a/server/src/test/java/org/apache/druid/client/coordinator/NoopCoordinatorClient.java b/server/src/test/java/org/apache/druid/client/coordinator/NoopCoordinatorClient.java index b8ec7d786726..f65be567ff04 100644 --- a/server/src/test/java/org/apache/druid/client/coordinator/NoopCoordinatorClient.java +++ b/server/src/test/java/org/apache/druid/client/coordinator/NoopCoordinatorClient.java @@ -92,7 +92,7 @@ public ListenableFuture getCompactionSnapshots(@Nullab } @Override - public ListenableFuture getCoordinatorConfig() + public ListenableFuture getCoordinatorDynamicConfig() { throw new UnsupportedOperationException(); } diff --git a/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java b/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java index b06d0e3f6f9c..f2a7234ae474 100644 --- a/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java +++ b/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java @@ -51,7 +51,6 @@ import org.apache.druid.segment.generator.SegmentGenerator; import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.metrics.NoopServiceEmitter; -import org.apache.druid.server.metrics.TestDynamicConfigurationManager; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.partition.NumberedShardSpec; import org.joda.time.Interval; @@ -134,7 +133,7 @@ public void setupTestBase() ForkJoinPool.commonPool(), QueryStackTests.DEFAULT_NOOP_SCHEDULER, new NoopServiceEmitter(), - new TestDynamicConfigurationManager() + null ); servers = new ArrayList<>(); } diff --git a/server/src/test/java/org/apache/druid/server/metrics/TestDynamicConfigurationManager.java b/server/src/test/java/org/apache/druid/server/metrics/TestDynamicConfigurationManager.java deleted file mode 100644 index c2034d6d56f7..000000000000 --- a/server/src/test/java/org/apache/druid/server/metrics/TestDynamicConfigurationManager.java +++ /dev/null @@ -1,63 +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.server.metrics; - -import com.google.common.collect.ImmutableSet; -import org.apache.druid.client.DynamicConfigurationManager; -import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; - -import java.util.Set; - -public class TestDynamicConfigurationManager extends DynamicConfigurationManager -{ - public TestDynamicConfigurationManager() - { - // TODO: finish and add tests. - super(null); - } - - @Override - public CoordinatorDynamicConfig getConfig() - { - return null; - } - - @Override - public Set getTargetCloneServers() - { - return ImmutableSet.of(); - } - - @Override - public Set getSourceClusterServers() - { - return ImmutableSet.of(); - } - - @Override - public void updateCloneServers(CoordinatorDynamicConfig updatedConfig) - { - } - - @Override - public void start() throws InterruptedException - { - } -} diff --git a/services/src/main/java/org/apache/druid/cli/CliBroker.java b/services/src/main/java/org/apache/druid/cli/CliBroker.java index 2b0e57c5b7f4..4bc08055d9e0 100644 --- a/services/src/main/java/org/apache/druid/cli/CliBroker.java +++ b/services/src/main/java/org/apache/druid/cli/CliBroker.java @@ -29,7 +29,7 @@ import org.apache.druid.client.BrokerSegmentWatcherConfig; import org.apache.druid.client.BrokerServerView; import org.apache.druid.client.CachingClusteredClient; -import org.apache.druid.client.DynamicConfigurationManager; +import org.apache.druid.client.CoordinatorDynamicConfigView; import org.apache.druid.client.DirectDruidClientFactory; import org.apache.druid.client.HttpServerInventoryViewResource; import org.apache.druid.client.InternalQueryConfig; @@ -170,7 +170,7 @@ protected List getModules() LifecycleModule.register(binder, Server.class); binder.bind(SegmentManager.class).in(LazySingleton.class); - binder.bind(DynamicConfigurationManager.class).in(ManageLifecycle.class); + binder.bind(CoordinatorDynamicConfigView.class).in(ManageLifecycle.class); binder.bind(ZkCoordinator.class).in(ManageLifecycle.class); binder.bind(ServerTypeConfig.class).toInstance(new ServerTypeConfig(ServerType.BROKER)); Jerseys.addResource(binder, HistoricalResource.class); diff --git a/services/src/main/java/org/apache/druid/cli/CliCoordinator.java b/services/src/main/java/org/apache/druid/cli/CliCoordinator.java index 85d5acf286b5..d1f01b63dfe3 100644 --- a/services/src/main/java/org/apache/druid/cli/CliCoordinator.java +++ b/services/src/main/java/org/apache/druid/cli/CliCoordinator.java @@ -38,7 +38,6 @@ import org.apache.druid.client.CoordinatorSegmentWatcherConfig; import org.apache.druid.client.CoordinatorServerView; import org.apache.druid.client.DirectDruidClientFactory; -import org.apache.druid.client.DynamicConfigurationManager; import org.apache.druid.client.HttpServerInventoryViewResource; import org.apache.druid.client.InternalQueryConfig; import org.apache.druid.client.coordinator.Coordinator; From fa359021451314a421fd5c408e949a60cddf9a86 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Fri, 11 Apr 2025 20:00:05 +0530 Subject: [PATCH 07/38] Add cloneQueryMode enum --- .../apache/druid/query/CloneQueryMode.java | 27 +++++++++++ .../org/apache/druid/query/QueryContext.java | 9 ++-- .../org/apache/druid/query/QueryContexts.java | 4 +- .../druid/client/CachingClusteredClient.java | 46 ++++++++++++++----- 4 files changed, 68 insertions(+), 18 deletions(-) create mode 100644 processing/src/main/java/org/apache/druid/query/CloneQueryMode.java diff --git a/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java b/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java new file mode 100644 index 000000000000..026677e7344f --- /dev/null +++ b/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java @@ -0,0 +1,27 @@ +/* + * 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.query; + +public enum CloneQueryMode +{ + ONLY, + INCLUDE, + EXCLUDE +} diff --git a/processing/src/main/java/org/apache/druid/query/QueryContext.java b/processing/src/main/java/org/apache/druid/query/QueryContext.java index ca5c1cefaddc..6dc9c86ee6f1 100644 --- a/processing/src/main/java/org/apache/druid/query/QueryContext.java +++ b/processing/src/main/java/org/apache/druid/query/QueryContext.java @@ -552,11 +552,12 @@ public boolean getEnableJoinFilterRewriteValueColumnFilters() ); } - public boolean getQueryUnmanagedServers() + public CloneQueryMode getQueryCloneMode() { - return getBoolean( - QueryContexts.QUERY_UNMANAGED_SERVERS, - QueryContexts.DEFAULT_QUERY_UNMANAGED_SERVERS + return getEnum( + QueryContexts.QUERY_CLONE_MODE, + CloneQueryMode.class, + QueryContexts.DEFAULT_QUERY_CLONE_MODE ); } diff --git a/processing/src/main/java/org/apache/druid/query/QueryContexts.java b/processing/src/main/java/org/apache/druid/query/QueryContexts.java index 85e612359ac0..3121e56775e7 100644 --- a/processing/src/main/java/org/apache/druid/query/QueryContexts.java +++ b/processing/src/main/java/org/apache/druid/query/QueryContexts.java @@ -65,7 +65,7 @@ public class QueryContexts public static final String JOIN_FILTER_REWRITE_MAX_SIZE_KEY = "joinFilterRewriteMaxSize"; public static final String MAX_NUMERIC_IN_FILTERS = "maxNumericInFilters"; public static final String CURSOR_AUTO_ARRANGE_FILTERS = "cursorAutoArrangeFilters"; - public static final String QUERY_UNMANAGED_SERVERS = "queryUnmanagedServers"; + public static final String QUERY_CLONE_MODE = "queryCloneMode"; // This flag controls whether a SQL join query with left scan should be attempted to be run as direct table access // instead of being wrapped inside a query. With direct table access enabled, Druid can push down the join operation to // data servers. @@ -150,7 +150,7 @@ public class QueryContexts public static final boolean DEFAULT_ENABLE_JOIN_FILTER_PUSH_DOWN = true; public static final boolean DEFAULT_ENABLE_JOIN_FILTER_REWRITE = true; public static final boolean DEFAULT_ENABLE_JOIN_FILTER_REWRITE_VALUE_COLUMN_FILTERS = false; - public static final boolean DEFAULT_QUERY_UNMANAGED_SERVERS = false; + public static final CloneQueryMode DEFAULT_QUERY_CLONE_MODE = CloneQueryMode.EXCLUDE; public static final boolean DEFAULT_ENABLE_REWRITE_JOIN_TO_FILTER = true; public static final long DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE = 10000; public static final boolean DEFAULT_ENABLE_SQL_JOIN_LEFT_SCAN_DIRECT = false; diff --git a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java index 59d37fbeade5..aa89215a4b9c 100644 --- a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java +++ b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java @@ -58,6 +58,7 @@ import org.apache.druid.query.BrokerParallelMergeConfig; import org.apache.druid.query.BySegmentResultValueClass; import org.apache.druid.query.CacheStrategy; +import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.Queries; import org.apache.druid.query.Query; import org.apache.druid.query.QueryContext; @@ -93,6 +94,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; @@ -606,13 +608,23 @@ private SortedMap> groupSegmentsByServer(Se final SortedMap> serverSegments = new TreeMap<>(); for (SegmentServerSelector segmentServer : segments) { Supplier> supplier = () -> { - boolean queryUnmanagedServers = query.context().getQueryUnmanagedServers(); - if (queryUnmanagedServers) { - // If this is a test query, ignore source servers. - return coordinatorDynamicConfigView.getSourceClusterServers(); - } else { - return coordinatorDynamicConfigView.getTargetCloneServers(); + CloneQueryMode cloneQueryMode = query.context().getQueryCloneMode(); + final Set serversToIgnore = new HashSet<>(); + + switch (cloneQueryMode) { + case ONLY: + // Remove clone sources, so that targets are queried. + serversToIgnore.addAll(coordinatorDynamicConfigView.getSourceClusterServers()); + break; + case EXCLUDE: + // Remove clone sources, so that targets are queried. + serversToIgnore.addAll(coordinatorDynamicConfigView.getTargetCloneServers()); + break; + case INCLUDE: + // Don't remove either + break; } + return serversToIgnore; }; final QueryableDruidServer queryableDruidServer = segmentServer.getServer() @@ -838,13 +850,23 @@ String computeResultLevelCachingEtag( boolean hasOnlyHistoricalSegments = true; for (SegmentServerSelector p : segments) { Supplier> supplier = () -> { - boolean queryUnmanagedServers = query.context().getQueryUnmanagedServers(); - if (queryUnmanagedServers) { - // If this is a test query, ignore source servers. - return coordinatorDynamicConfigView.getSourceClusterServers(); - } else { - return coordinatorDynamicConfigView.getTargetCloneServers(); + CloneQueryMode cloneQueryMode = query.context().getQueryCloneMode(); + final Set serversToIgnore = new HashSet<>(); + + switch (cloneQueryMode) { + case ONLY: + // Remove clone sources, so that targets are queried. + serversToIgnore.addAll(coordinatorDynamicConfigView.getSourceClusterServers()); + break; + case EXCLUDE: + // Remove clone sources, so that targets are queried. + serversToIgnore.addAll(coordinatorDynamicConfigView.getTargetCloneServers()); + break; + case INCLUDE: + // Don't remove either + break; } + return serversToIgnore; }; QueryableDruidServer queryableServer = p.getServer().pick(query, new HistoricalFilter(supplier)); if (queryableServer == null || !queryableServer.getServer().isSegmentReplicationTarget()) { From 9789f1fa66f067a0a2462493e2b4f2d0609a63c1 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Sat, 12 Apr 2025 09:17:42 +0530 Subject: [PATCH 08/38] Cleanup --- .../druid/client/CachingClusteredClient.java | 1 - .../client/selector/HistoricalFilter.java | 19 +++ .../server/coordinator/CloneDetails.java | 23 +++- .../coordinator/CloneStatusManager.java | 25 +++- .../coordinator/CoordinatorDynamicConfig.java | 1 + .../server/coordinator/DruidCoordinator.java | 7 +- ...Duty.java => BrokerDynamicConfigSync.java} | 9 +- .../CoordinatorDynamicConfigsResource.java | 2 +- .../server/http/DynamicConfigSyncer.java | 112 +++++++++--------- .../CoordinatorClientImplTest.java | 27 +++++ .../http/CoordinatorDynamicConfigTest.java | 82 ++++++++++--- .../java/org/apache/druid/cli/CliBroker.java | 2 +- 12 files changed, 217 insertions(+), 93 deletions(-) rename server/src/main/java/org/apache/druid/server/coordinator/duty/{SyncBrokerDuty.java => BrokerDynamicConfigSync.java} (81%) diff --git a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java index aa89215a4b9c..3c2f38681278 100644 --- a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java +++ b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java @@ -476,7 +476,6 @@ private Set computeSegmentsToQuery( } for (PartitionChunk chunk : filteredChunks) { ServerSelector server = chunk.getObject(); - final SegmentDescriptor segment = new SegmentDescriptor( holder.getInterval(), holder.getVersion(), diff --git a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java index db263859a979..89bcd6b5087e 100644 --- a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java +++ b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java @@ -1,3 +1,22 @@ +/* + * 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.client.selector; import com.google.common.collect.ImmutableSet; diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneDetails.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneDetails.java index 7ac5c4afde6a..3c4f2f14b2bf 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneDetails.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneDetails.java @@ -1,3 +1,22 @@ +/* + * 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.server.coordinator; import com.fasterxml.jackson.annotation.JsonCreator; @@ -34,8 +53,4 @@ public long getBytesRemaining() { return bytesRemaining; } - - public enum Status { - CLONING - } } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java index cac271bd6707..66bc01b7c133 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java @@ -1,3 +1,22 @@ +/* + * 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.server.coordinator; import com.google.errorprone.annotations.concurrent.GuardedBy; @@ -14,7 +33,8 @@ public class CloneStatusManager @GuardedBy("this") private final Map cloneStatusMap; - public CloneStatusManager() { + public CloneStatusManager() + { cloneStatusMap = new HashMap<>(); } @@ -34,7 +54,6 @@ public void updateStats(Map historicalMap, Map historicalMap, Map queuedSegment: targetServer.getQueuedSegments().entrySet()) { + for (Map.Entry queuedSegment : targetServer.getQueuedSegments().entrySet()) { if (queuedSegment.getValue().isLoad()) { segmentsLeft++; bytesLeft += queuedSegment.getKey().getSize(); diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java b/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java index dfb4d38a3b25..69ffd24161c8 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java @@ -370,6 +370,7 @@ public String toString() ", pauseCoordination=" + pauseCoordination + ", replicateAfterLoadTimeout=" + replicateAfterLoadTimeout + ", turboLoadingNodes=" + turboLoadingNodes + + ", cloneServers=" + cloneServers + '}'; } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java b/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java index 30b6c4e63a3c..5fa6c1b0a67b 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java @@ -83,7 +83,7 @@ import org.apache.druid.server.coordinator.duty.MetadataAction; import org.apache.druid.server.coordinator.duty.PrepareBalancerAndLoadQueues; import org.apache.druid.server.coordinator.duty.RunRules; -import org.apache.druid.server.coordinator.duty.SyncBrokerDuty; +import org.apache.druid.server.coordinator.duty.BrokerDynamicConfigSync; import org.apache.druid.server.coordinator.duty.UnloadUnusedSegments; import org.apache.druid.server.coordinator.loading.LoadQueuePeon; import org.apache.druid.server.coordinator.loading.LoadQueueTaskMaster; @@ -192,8 +192,7 @@ public DruidCoordinator( CompactionStatusTracker compactionStatusTracker ) { - this(config, metadataManager, serverInventoryView, emitter, scheduledExecutorFactory, overlordClient, taskMaster, loadQueueManager, serviceAnnouncer, self - , customDutyGroups, lookupCoordinatorManager, coordLeaderSelector, coordinatorSegmentMetadataCache, centralizedDatasourceSchemaConfig, compactionStatusTracker, null, null); + this(config, metadataManager, serverInventoryView, emitter, scheduledExecutorFactory, overlordClient, taskMaster, loadQueueManager, serviceAnnouncer, self, customDutyGroups, lookupCoordinatorManager, coordLeaderSelector, coordinatorSegmentMetadataCache, centralizedDatasourceSchemaConfig, compactionStatusTracker, null, null); } @Inject @@ -591,7 +590,7 @@ private List makeHistoricalManagementDuties() new MarkEternityTombstonesAsUnused(deleteSegments), new BalanceSegments(config.getCoordinatorPeriod()), new CloneHistoricals(loadQueueManager, cloneStatusManager), - new SyncBrokerDuty(dynamicConfigSyncer), + new BrokerDynamicConfigSync(dynamicConfigSyncer), new CollectLoadQueueStats() ); } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/duty/SyncBrokerDuty.java b/server/src/main/java/org/apache/druid/server/coordinator/duty/BrokerDynamicConfigSync.java similarity index 81% rename from server/src/main/java/org/apache/druid/server/coordinator/duty/SyncBrokerDuty.java rename to server/src/main/java/org/apache/druid/server/coordinator/duty/BrokerDynamicConfigSync.java index 83d7694348cd..078373d98987 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/duty/SyncBrokerDuty.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/duty/BrokerDynamicConfigSync.java @@ -24,11 +24,14 @@ import javax.annotation.Nullable; -public class SyncBrokerDuty implements CoordinatorDuty +/** + * Duty to periodically broadcast the coordinator dynamic configuration to all brokers. + */ +public class BrokerDynamicConfigSync implements CoordinatorDuty { private final DynamicConfigSyncer dynamicConfigSyncer; - public SyncBrokerDuty(DynamicConfigSyncer dynamicConfigSyncer) + public BrokerDynamicConfigSync(DynamicConfigSyncer dynamicConfigSyncer) { this.dynamicConfigSyncer = dynamicConfigSyncer; } @@ -37,7 +40,7 @@ public SyncBrokerDuty(DynamicConfigSyncer dynamicConfigSyncer) @Override public DruidCoordinatorRuntimeParams run(DruidCoordinatorRuntimeParams params) { - dynamicConfigSyncer.updateConfigIfNeeded(); + dynamicConfigSyncer.queueBroadcastConfig(); return params; } } diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java index 94882dca0df4..7c9b63702c49 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java @@ -87,7 +87,7 @@ public Response setDynamicConfigs( ); if (setResult.isOk()) { - dynamicConfigSyncer.updateConfigIfNeeded(); + dynamicConfigSyncer.queueBroadcastConfig(); return Response.ok().build(); } else { return Response.status(Response.Status.BAD_REQUEST) diff --git a/server/src/main/java/org/apache/druid/server/http/DynamicConfigSyncer.java b/server/src/main/java/org/apache/druid/server/http/DynamicConfigSyncer.java index 31f1685f21b8..6968d36aa71a 100644 --- a/server/src/main/java/org/apache/druid/server/http/DynamicConfigSyncer.java +++ b/server/src/main/java/org/apache/druid/server/http/DynamicConfigSyncer.java @@ -22,8 +22,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableSet; import com.google.inject.Inject; -import org.apache.druid.client.DruidServer; import org.apache.druid.client.ServerInventoryView; +import org.apache.druid.discovery.NodeRole; import org.apache.druid.guice.annotations.EscalatedGlobal; import org.apache.druid.guice.annotations.Json; import org.apache.druid.java.util.common.concurrent.Execs; @@ -48,97 +48,95 @@ import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; - -import static org.apache.druid.discovery.NodeRole.BROKER; public class DynamicConfigSyncer { private static final Logger log = new Logger(DynamicConfigSyncer.class); - protected final ExecutorService exec; - private final ServiceClientFactory clientFactory; + private static final String BROKER_UPDATE_PATH = "/druid-internal/v1/dynamicConfiguration/coordinatorDynamicConfig"; + private final CoordinatorConfigManager configManager; - private final List inSyncBrokers; - private final ObjectMapper objectMapper; private final ServerInventoryView serverInventoryView; + private final ObjectMapper jsonMapper; + private final AtomicReference lastKnownConfig = new AtomicReference<>(); + private final ServiceClientFactory clientFactory; + private final ExecutorService exec; + private final List inSyncBrokers; @Inject public DynamicConfigSyncer( @EscalatedGlobal final ServiceClientFactory clientFactory, - CoordinatorConfigManager configManager, - @Json ObjectMapper objectMapper, - ServerInventoryView serverInventoryView - ) + final CoordinatorConfigManager configManager, + @Json final ObjectMapper jsonMapper, + final ServerInventoryView serverInventoryView + ) { this.clientFactory = clientFactory; this.configManager = configManager; - this.objectMapper = objectMapper; + this.jsonMapper = jsonMapper; this.serverInventoryView = serverInventoryView; this.exec = Execs.singleThreaded("DynamicConfigSyncer-%d"); - this.inSyncBrokers = new ArrayList<>(); + this.inSyncBrokers = new ArrayList<>(); // TODO: concurrency } - private void updateBroker(DruidServerMetadata broker) + public void queueBroadcastConfig() { - ServiceLocation serviceLocation = ServiceLocation.fromDruidServerMetadata(broker); - ServiceClient serviceClient = clientFactory.makeClient( - BROKER.getJsonName(), - new FixedServiceLocator(serviceLocation), + final CoordinatorDynamicConfig currentDynamicConfig = configManager.getCurrentDynamicConfig(); + if (!currentDynamicConfig.equals(lastKnownConfig.get())) { + // Config has changed, clear the inSync list. + lastKnownConfig.set(currentDynamicConfig); + inSyncBrokers.clear(); + } + + for (DruidServerMetadata broker : getCurrentBrokers()) { + exec.submit(() -> syncConfigToBroker(broker)); + } + } + + private void syncConfigToBroker(DruidServerMetadata broker) + { + final ServiceLocation brokerLocation = ServiceLocation.fromDruidServerMetadata(broker); + final ServiceClient brokerClient = clientFactory.makeClient( + NodeRole.BROKER.getJsonName(), + new FixedServiceLocator(brokerLocation), StandardRetryPolicy.builder().maxAttempts(6).build() ); try { - RequestBuilder requestBuilder = - new RequestBuilder(HttpMethod.POST, "/druid-internal/v1/dynamicConfiguration/coordinatorDynamicConfig") - .jsonContent(objectMapper, configManager.getCurrentDynamicConfig()); + final RequestBuilder requestBuilder = + new RequestBuilder(HttpMethod.POST, BROKER_UPDATE_PATH) + .jsonContent(jsonMapper, configManager.getCurrentDynamicConfig()); - BytesFullResponseHolder request = serviceClient.request( - requestBuilder, - new BytesFullResponseHandler() - ); - HttpResponseStatus status = request.getStatus(); + final BytesFullResponseHolder responseHolder = brokerClient.request(requestBuilder, new BytesFullResponseHandler()); + final HttpResponseStatus status = responseHolder.getStatus(); if (status.equals(HttpResponseStatus.OK)) { - log.info("Successfully posted dynamic configs to [%s]", broker.getHost()); inSyncBrokers.add(broker.getHost()); - log.info("In sync: [%s]", inSyncBrokers); } else { - log.error("Error [%s] while posting dynamic configs to [%s]", status.getCode(), broker.getHostAndPort()); + log.error( + "Received status [%s] while posting dynamic configs to broker[%s]", + status.getCode(), + broker.getHostAndPort() + ); } } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public void updateConfigIfNeeded() - { - log.info("Running Broker sync duty"); - CoordinatorDynamicConfig currentDynamicConfig = configManager.getCurrentDynamicConfig(); - if (currentDynamicConfig.equals(lastKnownConfig.get())) { - log.info("No need to change, already latest"); - } else { - lastKnownConfig.set(currentDynamicConfig); - inSyncBrokers.clear(); - getCurrentBrokers().forEach(broker -> exec.submit(() -> updateBroker(broker))); + // Catch and ignore the exception, wait for the next sync. + log.error( + e, + "Exception while syncing dynamic configuration to broker[%s]", + broker.getHostAndPort() + ); } } - public Set getCurrentBrokers() + private Set getCurrentBrokers() { - // TODO: work around - Set collect = serverInventoryView - .getInventory() - .stream() - .filter(ds -> ServerType.BROKER.equals(ds.getType())) - .map(DruidServer::getMetadata) - .collect(Collectors.toSet()); - log.info("SERVER VIEW BROKERS: [%s]", collect); + // TODO: Inventory view seems to be returning only an empty list, local work around for now. return ImmutableSet.of( - new DruidServerMetadata( - "localhost:8082", - "localhost:8082", - null, 0, ServerType.BROKER, "tier1", 0) + new DruidServerMetadata( + "localhost:8082", + "localhost:8082", + null, 0, ServerType.BROKER, "tier1", 0) ); } diff --git a/server/src/test/java/org/apache/druid/client/coordinator/CoordinatorClientImplTest.java b/server/src/test/java/org/apache/druid/client/coordinator/CoordinatorClientImplTest.java index 1cf7f86f352c..67180d9e1b2e 100644 --- a/server/src/test/java/org/apache/druid/client/coordinator/CoordinatorClientImplTest.java +++ b/server/src/test/java/org/apache/druid/client/coordinator/CoordinatorClientImplTest.java @@ -44,6 +44,7 @@ import org.apache.druid.server.coordination.DruidServerMetadata; import org.apache.druid.server.coordination.ServerType; import org.apache.druid.server.coordinator.AutoCompactionSnapshot; +import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.PruneLoadSpec; import org.apache.druid.timeline.partition.NumberedShardSpec; @@ -423,4 +424,30 @@ public void test_getCompactionSnapshots_nonNullDataSource() throws Exception coordinatorClient.getCompactionSnapshots("ds1").get() ); } + + @Test + public void test_getCoordinatorDynamicConfig() throws Exception + { + CoordinatorDynamicConfig config = CoordinatorDynamicConfig + .builder() + .withMaxSegmentsToMove(105) + .withReplicantLifetime(500) + .withReplicationThrottleLimit(5) + .build(); + + serviceClient.expectAndRespond( + new RequestBuilder( + HttpMethod.GET, + "/druid/coordinator/v1/config" + ), + HttpResponseStatus.OK, + ImmutableMap.of(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON), + DefaultObjectMapper.INSTANCE.writeValueAsBytes(config) + ); + + Assert.assertEquals( + config, + coordinatorClient.getCoordinatorDynamicConfig().get() + ); + } } diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java index 98324792ef7b..c249de5da3c8 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java @@ -20,6 +20,7 @@ package org.apache.druid.server.http; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import org.apache.druid.segment.TestHelper; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; @@ -28,6 +29,7 @@ import org.junit.Test; import javax.annotation.Nullable; +import java.util.Map; import java.util.Set; public class CoordinatorDynamicConfigTest @@ -52,7 +54,8 @@ public void testSerde() throws Exception + " \"decommissioningNodes\": [\"host1\", \"host2\"],\n" + " \"pauseCoordination\": false,\n" + " \"replicateAfterLoadTimeout\": false,\n" - + " \"turboLoadingNodes\":[\"host1\", \"host3\"]\n" + + " \"turboLoadingNodes\":[\"host1\", \"host3\"],\n" + + " \"cloneServers\":{\"host5\": \"host6\"}\n" + "}\n"; CoordinatorDynamicConfig actual = mapper.readValue( @@ -67,6 +70,7 @@ public void testSerde() throws Exception ImmutableSet decommissioning = ImmutableSet.of("host1", "host2"); ImmutableSet whitelist = ImmutableSet.of("test1", "test2"); ImmutableSet turboLoadingNodes = ImmutableSet.of("host1", "host3"); + ImmutableMap cloneServers = ImmutableMap.of("host5", "host6"); assertConfig( actual, 1, @@ -81,7 +85,8 @@ public void testSerde() throws Exception decommissioning, false, false, - turboLoadingNodes + turboLoadingNodes, + cloneServers ); actual = CoordinatorDynamicConfig.builder().withDecommissioningNodes(ImmutableSet.of("host1")).build(actual); @@ -99,7 +104,8 @@ public void testSerde() throws Exception ImmutableSet.of("host1"), false, false, - turboLoadingNodes + turboLoadingNodes, + cloneServers ); actual = CoordinatorDynamicConfig.builder().build(actual); @@ -117,7 +123,8 @@ public void testSerde() throws Exception ImmutableSet.of("host1"), false, false, - turboLoadingNodes + turboLoadingNodes, + cloneServers ); actual = CoordinatorDynamicConfig.builder().withPauseCoordination(true).build(actual); @@ -135,7 +142,8 @@ public void testSerde() throws Exception ImmutableSet.of("host1"), true, false, - turboLoadingNodes + turboLoadingNodes, + cloneServers ); actual = CoordinatorDynamicConfig.builder().withReplicateAfterLoadTimeout(true).build(actual); @@ -153,7 +161,8 @@ public void testSerde() throws Exception ImmutableSet.of("host1"), true, true, - turboLoadingNodes + turboLoadingNodes, + cloneServers ); actual = CoordinatorDynamicConfig.builder().build(actual); @@ -171,7 +180,8 @@ public void testSerde() throws Exception ImmutableSet.of("host1"), true, true, - turboLoadingNodes + turboLoadingNodes, + cloneServers ); actual = CoordinatorDynamicConfig.builder().withKillTaskSlotRatio(0.1).build(actual); @@ -189,7 +199,8 @@ public void testSerde() throws Exception ImmutableSet.of("host1"), true, true, - turboLoadingNodes + turboLoadingNodes, + cloneServers ); actual = CoordinatorDynamicConfig.builder().withMaxKillTaskSlots(5).build(actual); @@ -207,7 +218,29 @@ public void testSerde() throws Exception ImmutableSet.of("host1"), true, true, - turboLoadingNodes + turboLoadingNodes, + cloneServers + ); + + actual = CoordinatorDynamicConfig.builder() + .withTurboLoadingNodes(ImmutableSet.of("host3")) + .withCloneServers(ImmutableMap.of("host3", "host4")).build(actual); + assertConfig( + actual, + 1, + 1, + 1, + 1, + 2, + whitelist, + 0.1, + 5, + 1, + ImmutableSet.of("host1"), + true, + true, + ImmutableSet.of("host3"), + ImmutableMap.of("host3", "host4") ); } @@ -287,7 +320,8 @@ public void testDecommissioningParametersBackwardCompatibility() throws Exceptio + " \"balancerComputeThreads\": 2, \n" + " \"killDataSourceWhitelist\": [\"test1\",\"test2\"],\n" + " \"maxSegmentsInNodeLoadingQueue\": 1,\n" - + " \"turboLoadingNodes\": [\"host3\",\"host4\"]\n" + + " \"turboLoadingNodes\": [\"host3\",\"host4\"],\n" + + " \"cloneServers\": {\"host3\":\"host4\", \"host5\":\"host6\"}\n" + "}\n"; CoordinatorDynamicConfig actual = mapper.readValue( @@ -302,6 +336,7 @@ public void testDecommissioningParametersBackwardCompatibility() throws Exceptio ImmutableSet decommissioning = ImmutableSet.of(); ImmutableSet whitelist = ImmutableSet.of("test1", "test2"); ImmutableSet turboLoading = ImmutableSet.of("host3", "host4"); + ImmutableMap cloneServers = ImmutableMap.of("host3", "host4", "host5", "host6"); assertConfig( actual, 1, @@ -316,7 +351,8 @@ public void testDecommissioningParametersBackwardCompatibility() throws Exceptio decommissioning, false, false, - turboLoading + turboLoading, + cloneServers ); actual = CoordinatorDynamicConfig.builder().withDecommissioningNodes(ImmutableSet.of("host1")).build(actual); @@ -334,7 +370,8 @@ public void testDecommissioningParametersBackwardCompatibility() throws Exceptio ImmutableSet.of("host1"), false, false, - turboLoading + turboLoading, + cloneServers ); actual = CoordinatorDynamicConfig.builder().build(actual); @@ -352,7 +389,8 @@ public void testDecommissioningParametersBackwardCompatibility() throws Exceptio ImmutableSet.of("host1"), false, false, - turboLoading + turboLoading, + cloneServers ); } @@ -392,7 +430,8 @@ public void testSerdeWithStringInKillDataSourceWhitelist() throws Exception ImmutableSet.of(), false, false, - ImmutableSet.of() + ImmutableSet.of(), + ImmutableMap.of() ); } @@ -432,7 +471,8 @@ public void testHandleMissingPercentOfSegmentsToConsiderPerMove() throws Excepti decommissioning, false, false, - ImmutableSet.of() + ImmutableSet.of(), + ImmutableMap.of() ); } @@ -468,7 +508,8 @@ public void testDeserializeWithoutMaxSegmentsInNodeLoadingQueue() throws Excepti ImmutableSet.of(), false, false, - ImmutableSet.of() + ImmutableSet.of(), + ImmutableMap.of() ); } @@ -491,7 +532,8 @@ public void testBuilderDefaults() emptyList, false, false, - ImmutableSet.of() + ImmutableSet.of(), + ImmutableMap.of() ); } @@ -517,7 +559,8 @@ public void testBuilderWithDefaultSpecificDataSourcesToKillUnusedSegmentsInSpeci ImmutableSet.of(), false, false, - ImmutableSet.of() + ImmutableSet.of(), + ImmutableMap.of() ); } @@ -570,7 +613,8 @@ private void assertConfig( Set decommissioningNodes, boolean pauseCoordination, boolean replicateAfterLoadTimeout, - Set turboLoadingNodes + Set turboLoadingNodes, + Map cloneServers ) { Assert.assertEquals( diff --git a/services/src/main/java/org/apache/druid/cli/CliBroker.java b/services/src/main/java/org/apache/druid/cli/CliBroker.java index 4bc08055d9e0..d69376b0e477 100644 --- a/services/src/main/java/org/apache/druid/cli/CliBroker.java +++ b/services/src/main/java/org/apache/druid/cli/CliBroker.java @@ -60,8 +60,8 @@ import org.apache.druid.query.lookup.LookupModule; import org.apache.druid.server.BrokerQueryResource; import org.apache.druid.server.ClientInfoResource; -import org.apache.druid.server.DruidInternalDynamicConfigResource; import org.apache.druid.server.ClientQuerySegmentWalker; +import org.apache.druid.server.DruidInternalDynamicConfigResource; import org.apache.druid.server.ResponseContextConfig; import org.apache.druid.server.SegmentManager; import org.apache.druid.server.SubqueryGuardrailHelper; From 34e7d78d8c2d21228dfcf8944e5856e2facfd425 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Sat, 12 Apr 2025 10:33:29 +0530 Subject: [PATCH 09/38] Cleanup --- .../org/apache/druid/query/QueryContext.java | 6 +- .../org/apache/druid/query/QueryContexts.java | 4 +- .../apache/druid/query/QueryContextsTest.java | 9 ++ .../druid/client/CachingClusteredClient.java | 4 +- .../DruidInternalDynamicConfigResource.java | 4 + .../coordinator/CloneStatusManager.java | 8 +- .../coordinator/CloneStatusMetrics.java | 121 ++++++++++++++++++ .../server/coordinator/DruidCoordinator.java | 12 +- .../duty/BrokerDynamicConfigSync.java | 10 +- .../coordinator/duty/CloneHistoricals.java | 27 ++-- ...va => CoordinatorDynamicConfigSyncer.java} | 6 +- .../CoordinatorDynamicConfigsResource.java | 8 +- .../server/http/CoordinatorResource.java | 12 +- .../coordinator/CloneStatusMetricsTest.java} | 42 ++---- .../http/CoordinatorDynamicConfigTest.java | 1 + .../org/apache/druid/cli/CliCoordinator.java | 4 +- 16 files changed, 199 insertions(+), 79 deletions(-) create mode 100644 server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java rename server/src/main/java/org/apache/druid/server/http/{DynamicConfigSyncer.java => CoordinatorDynamicConfigSyncer.java} (97%) rename server/src/{main/java/org/apache/druid/server/coordinator/CloneDetails.java => test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java} (53%) diff --git a/processing/src/main/java/org/apache/druid/query/QueryContext.java b/processing/src/main/java/org/apache/druid/query/QueryContext.java index 6dc9c86ee6f1..17ddcd3aac03 100644 --- a/processing/src/main/java/org/apache/druid/query/QueryContext.java +++ b/processing/src/main/java/org/apache/druid/query/QueryContext.java @@ -552,12 +552,12 @@ public boolean getEnableJoinFilterRewriteValueColumnFilters() ); } - public CloneQueryMode getQueryCloneMode() + public CloneQueryMode getCloneQueryMode() { return getEnum( - QueryContexts.QUERY_CLONE_MODE, + QueryContexts.CLONE_QUERY_MODE, CloneQueryMode.class, - QueryContexts.DEFAULT_QUERY_CLONE_MODE + QueryContexts.DEFAULT_CLONE_QUERY_MODE ); } diff --git a/processing/src/main/java/org/apache/druid/query/QueryContexts.java b/processing/src/main/java/org/apache/druid/query/QueryContexts.java index 3121e56775e7..cef3051b6c74 100644 --- a/processing/src/main/java/org/apache/druid/query/QueryContexts.java +++ b/processing/src/main/java/org/apache/druid/query/QueryContexts.java @@ -65,7 +65,7 @@ public class QueryContexts public static final String JOIN_FILTER_REWRITE_MAX_SIZE_KEY = "joinFilterRewriteMaxSize"; public static final String MAX_NUMERIC_IN_FILTERS = "maxNumericInFilters"; public static final String CURSOR_AUTO_ARRANGE_FILTERS = "cursorAutoArrangeFilters"; - public static final String QUERY_CLONE_MODE = "queryCloneMode"; + public static final String CLONE_QUERY_MODE = "cloneQueryMode"; // This flag controls whether a SQL join query with left scan should be attempted to be run as direct table access // instead of being wrapped inside a query. With direct table access enabled, Druid can push down the join operation to // data servers. @@ -150,7 +150,7 @@ public class QueryContexts public static final boolean DEFAULT_ENABLE_JOIN_FILTER_PUSH_DOWN = true; public static final boolean DEFAULT_ENABLE_JOIN_FILTER_REWRITE = true; public static final boolean DEFAULT_ENABLE_JOIN_FILTER_REWRITE_VALUE_COLUMN_FILTERS = false; - public static final CloneQueryMode DEFAULT_QUERY_CLONE_MODE = CloneQueryMode.EXCLUDE; + public static final CloneQueryMode DEFAULT_CLONE_QUERY_MODE = CloneQueryMode.EXCLUDE; public static final boolean DEFAULT_ENABLE_REWRITE_JOIN_TO_FILTER = true; public static final long DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE = 10000; public static final boolean DEFAULT_ENABLE_SQL_JOIN_LEFT_SCAN_DIRECT = false; diff --git a/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java b/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java index 64538f33d8dd..3c7ab7f9913e 100644 --- a/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java +++ b/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java @@ -144,6 +144,15 @@ public void testDefaultPlanTimeBoundarySql() ); } + @Test + public void testDefaultCloneQueryMode() + { + Assert.assertEquals( + CloneQueryMode.EXCLUDE, + QueryContext.empty().getCloneQueryMode() + ); + } + @Test public void testCatalogValidationEnabled() { diff --git a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java index 3c2f38681278..9ae65dd4e1d0 100644 --- a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java +++ b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java @@ -607,7 +607,7 @@ private SortedMap> groupSegmentsByServer(Se final SortedMap> serverSegments = new TreeMap<>(); for (SegmentServerSelector segmentServer : segments) { Supplier> supplier = () -> { - CloneQueryMode cloneQueryMode = query.context().getQueryCloneMode(); + CloneQueryMode cloneQueryMode = query.context().getCloneQueryMode(); final Set serversToIgnore = new HashSet<>(); switch (cloneQueryMode) { @@ -849,7 +849,7 @@ String computeResultLevelCachingEtag( boolean hasOnlyHistoricalSegments = true; for (SegmentServerSelector p : segments) { Supplier> supplier = () -> { - CloneQueryMode cloneQueryMode = query.context().getQueryCloneMode(); + CloneQueryMode cloneQueryMode = query.context().getCloneQueryMode(); final Set serversToIgnore = new HashSet<>(); switch (cloneQueryMode) { diff --git a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java index a6e8c104d8de..e3aab85bafed 100644 --- a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java +++ b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java @@ -20,8 +20,10 @@ package org.apache.druid.server; import com.google.inject.Inject; +import com.sun.jersey.spi.container.ResourceFilters; import org.apache.druid.client.CoordinatorDynamicConfigView; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; +import org.apache.druid.server.http.security.ConfigResourceFilter; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -44,6 +46,7 @@ public DruidInternalDynamicConfigResource(CoordinatorDynamicConfigView coordinat @GET @Produces(MediaType.APPLICATION_JSON) + @ResourceFilters(ConfigResourceFilter.class) @Path("/coordinatorDynamicConfig") public Response getDatasource() { @@ -52,6 +55,7 @@ public Response getDatasource() @POST @Consumes(MediaType.APPLICATION_JSON) + @ResourceFilters(ConfigResourceFilter.class) @Path("/coordinatorDynamicConfig") public Response setDatasource(final CoordinatorDynamicConfig dynamicConfig) { diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java index 66bc01b7c133..6d8bfab849bf 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java @@ -31,14 +31,14 @@ public class CloneStatusManager { private static final Logger log = new Logger(CloneStatusManager.class); @GuardedBy("this") - private final Map cloneStatusMap; + private final Map cloneStatusMap; public CloneStatusManager() { cloneStatusMap = new HashMap<>(); } - public Map getCloneStatusMap() + public Map getCloneStatusMap() { synchronized (this) { return cloneStatusMap; @@ -59,7 +59,7 @@ public void updateStats(Map historicalMap, Map historicalMap, Map inSyncBrokers; @Inject - public DynamicConfigSyncer( + public CoordinatorDynamicConfigSyncer( @EscalatedGlobal final ServiceClientFactory clientFactory, final CoordinatorConfigManager configManager, @Json final ObjectMapper jsonMapper, diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java index 7c9b63702c49..54ac5e8da016 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java @@ -49,18 +49,18 @@ public class CoordinatorDynamicConfigsResource { private final CoordinatorConfigManager manager; private final AuditManager auditManager; - private final DynamicConfigSyncer dynamicConfigSyncer; + private final CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer; @Inject public CoordinatorDynamicConfigsResource( CoordinatorConfigManager manager, AuditManager auditManager, - DynamicConfigSyncer dynamicConfigSyncer + CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer ) { this.manager = manager; this.auditManager = auditManager; - this.dynamicConfigSyncer = dynamicConfigSyncer; + this.coordinatorDynamicConfigSyncer = coordinatorDynamicConfigSyncer; } @GET @@ -87,7 +87,7 @@ public Response setDynamicConfigs( ); if (setResult.isOk()) { - dynamicConfigSyncer.queueBroadcastConfig(); + coordinatorDynamicConfigSyncer.queueBroadcastConfig(); return Response.ok().build(); } else { return Response.status(Response.Status.BAD_REQUEST) diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java index 37b68cbc2079..32b20cf33759 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java @@ -45,21 +45,21 @@ public class CoordinatorResource { private final DruidCoordinator coordinator; private final CloneStatusManager cloneStatusManager; - private final DynamicConfigSyncer dynamicConfigSyncer; + private final CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer; public CoordinatorResource(DruidCoordinator coordinator) { this.coordinator = coordinator; this.cloneStatusManager = null; - dynamicConfigSyncer = null; + this.coordinatorDynamicConfigSyncer = null; } @Inject - public CoordinatorResource(DruidCoordinator coordinator, CloneStatusManager cloneStatusManager, DynamicConfigSyncer dynamicConfigSyncer) + public CoordinatorResource(DruidCoordinator coordinator, CloneStatusManager cloneStatusManager, CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer) { this.coordinator = coordinator; this.cloneStatusManager = cloneStatusManager; - this.dynamicConfigSyncer = dynamicConfigSyncer; + this.coordinatorDynamicConfigSyncer = coordinatorDynamicConfigSyncer; } @GET @@ -173,14 +173,16 @@ public Response getStatusOfDuties() @GET @Path("/brokerConfigurationStatus") + @ResourceFilters(StateResourceFilter.class) @Produces(MediaType.APPLICATION_JSON) public Response getBrokerStatus() { - return Response.ok(dynamicConfigSyncer.getInSyncBrokers()).build(); + return Response.ok(coordinatorDynamicConfigSyncer.getInSyncBrokers()).build(); } @GET @Path("/cloneStatus") + @ResourceFilters(StateResourceFilter.class) @Produces(MediaType.APPLICATION_JSON) public Response getCloneStatus() { diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneDetails.java b/server/src/test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java similarity index 53% rename from server/src/main/java/org/apache/druid/server/coordinator/CloneDetails.java rename to server/src/test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java index 3c4f2f14b2bf..0a34305cb382 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneDetails.java +++ b/server/src/test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java @@ -19,38 +19,18 @@ package org.apache.druid.server.coordinator; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.druid.jackson.DefaultObjectMapper; +import org.junit.Assert; +import org.junit.Test; -public class CloneDetails +public class CloneStatusMetricsTest { - final String sourceServer; - final long segmentsRemaining; - final long bytesRemaining; - - @JsonCreator - public CloneDetails(@JsonProperty String sourceServer, @JsonProperty long segmentsRemaining, @JsonProperty long bytesRemaining) - { - this.sourceServer = sourceServer; - this.segmentsRemaining = segmentsRemaining; - this.bytesRemaining = bytesRemaining; - } - - @JsonProperty - public String getSourceServer() - { - return sourceServer; - } - - @JsonProperty - public long getSegmentsRemaining() - { - return segmentsRemaining; - } - - @JsonProperty - public long getBytesRemaining() + @Test + public void testSerde() throws Exception { - return bytesRemaining; + CloneStatusMetrics metrics = new CloneStatusMetrics("host2", 1, 3012, 10, 100); + byte[] bytes = DefaultObjectMapper.INSTANCE.writeValueAsBytes(metrics); + CloneStatusMetrics deserialized = DefaultObjectMapper.INSTANCE.readValue(bytes, CloneStatusMetrics.class); + Assert.assertEquals(deserialized, metrics); } -} +} \ No newline at end of file diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java index c249de5da3c8..0aa43a42ec8f 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java @@ -636,6 +636,7 @@ private void assertConfig( Assert.assertEquals(pauseCoordination, config.getPauseCoordination()); Assert.assertEquals(replicateAfterLoadTimeout, config.getReplicateAfterLoadTimeout()); Assert.assertEquals(turboLoadingNodes, config.getTurboLoadingNodes()); + Assert.assertEquals(cloneServers, config.getCloneServers()); } private static int getDefaultNumBalancerThreads() diff --git a/services/src/main/java/org/apache/druid/cli/CliCoordinator.java b/services/src/main/java/org/apache/druid/cli/CliCoordinator.java index d1f01b63dfe3..67e4c3aa0046 100644 --- a/services/src/main/java/org/apache/druid/cli/CliCoordinator.java +++ b/services/src/main/java/org/apache/druid/cli/CliCoordinator.java @@ -117,7 +117,7 @@ import org.apache.druid.server.http.CoordinatorRedirectInfo; import org.apache.druid.server.http.CoordinatorResource; import org.apache.druid.server.http.DataSourcesResource; -import org.apache.druid.server.http.DynamicConfigSyncer; +import org.apache.druid.server.http.CoordinatorDynamicConfigSyncer; import org.apache.druid.server.http.IntervalsResource; import org.apache.druid.server.http.LookupCoordinatorResource; import org.apache.druid.server.http.MetadataResource; @@ -226,7 +226,7 @@ public void configure(Binder binder) binder.bind(DruidCoordinatorConfig.class); binder.bind(RedirectFilter.class).in(LazySingleton.class); - binder.bind(DynamicConfigSyncer.class).in(LazySingleton.class); + binder.bind(CoordinatorDynamicConfigSyncer.class).in(LazySingleton.class); if (beOverlord) { binder.bind(RedirectInfo.class).to(CoordinatorOverlordRedirectInfo.class).in(LazySingleton.class); } else { From 4263706c95943709dfd65da0a3103f5fbf660b1d Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Sat, 12 Apr 2025 16:09:17 +0530 Subject: [PATCH 10/38] Rewrite status API --- .../coordinator/CloneStatusManager.java | 60 +++++++++++-------- .../coordinator/CloneStatusMetrics.java | 40 +++++++------ .../server/http/CoordinatorResource.java | 18 +++--- .../coordinator/CloneStatusMetricsTest.java | 4 +- .../server/http/CoordinatorResourceTest.java | 10 ++-- 5 files changed, 75 insertions(+), 57 deletions(-) diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java index 6d8bfab849bf..90ec715d1ca1 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java @@ -19,60 +19,72 @@ package org.apache.druid.server.coordinator; -import com.google.errorprone.annotations.concurrent.GuardedBy; -import org.apache.druid.java.util.common.logger.Logger; +import com.google.common.collect.ImmutableMap; import org.apache.druid.server.coordinator.loading.SegmentAction; import org.apache.druid.timeline.DataSegment; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; public class CloneStatusManager { - private static final Logger log = new Logger(CloneStatusManager.class); - @GuardedBy("this") - private final Map cloneStatusMap; + private final AtomicReference> cloneStatusSnapshot; public CloneStatusManager() { - cloneStatusMap = new HashMap<>(); + this.cloneStatusSnapshot = new AtomicReference<>(ImmutableMap.of());; } - public Map getCloneStatusMap() + public Map getStatusForAllServers() { - synchronized (this) { - return cloneStatusMap; - } + return cloneStatusSnapshot.get(); + } + + public CloneStatusMetrics getStatusForServer(String targetServer) + { + return cloneStatusSnapshot.get().get(targetServer); } public void updateStats(Map historicalMap, Map cloneServers) { - synchronized (this) { - cloneStatusMap.clear(); + final Map newStatusMap = new HashMap<>(); - for (Map.Entry entry : cloneServers.entrySet()) { - String targetServerName = entry.getKey(); - ServerHolder targetServer = historicalMap.get(entry.getKey()); - String sourceServerName = entry.getValue(); + for (Map.Entry entry : cloneServers.entrySet()) { + final String targetServerName = entry.getKey(); + final ServerHolder targetServer = historicalMap.get(entry.getKey()); + final String sourceServerName = entry.getValue(); - int segmentsLeft = 0; - long bytesLeft = 0; + long segmentLoad = 0L; + long bytesLeft = 0L; + long segmentDrop = 0L; - if (targetServer == null) { - cloneStatusMap.put(targetServerName, new CloneStatusMetrics(sourceServerName, 0, 0, 0, 0)); - continue; + CloneStatusMetrics newStatus; + if (targetServer == null) { + newStatus = CloneStatusMetrics.unknown(sourceServerName); + } else { + CloneStatusMetrics.Status status; + + if (!historicalMap.containsKey(sourceServerName)) { + status = CloneStatusMetrics.Status.SOURCE_SERVER_MISSING; + } else { + status = CloneStatusMetrics.Status.LOADING; } for (Map.Entry queuedSegment : targetServer.getQueuedSegments().entrySet()) { if (queuedSegment.getValue().isLoad()) { - segmentsLeft++; + segmentLoad += 1; bytesLeft += queuedSegment.getKey().getSize(); + } else { + segmentDrop += 1; } } - - cloneStatusMap.put(targetServerName, new CloneStatusMetrics(sourceServerName, 0, 0, segmentsLeft, bytesLeft)); + newStatus = new CloneStatusMetrics(sourceServerName, status, segmentLoad, segmentDrop, bytesLeft); } + newStatusMap.put(targetServerName, newStatus); } + + cloneStatusSnapshot.set(newStatusMap); } } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java index d5141ea4923e..c8cb2b822eb7 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java @@ -27,25 +27,25 @@ public class CloneStatusMetrics { private final String sourceServer; + private final Status status; private final long segmentLoadsRemaining; private final long segmenetsDropsRemaining; private final long bytesRemaining; - private final long segmentChangesInLastRun; @JsonCreator public CloneStatusMetrics( @JsonProperty("sourceServer") String sourceServer, + @JsonProperty("status") Status status, @JsonProperty("segmentLoadsRemaining") long segmentLoadsRemaining, @JsonProperty("segmenetsDropsRemaining") long segmenetsDropsRemaining, - @JsonProperty("bytesRemaining") long bytesRemaining, - @JsonProperty("segmentChangesInLastRun") long segmentChangesInLastRun + @JsonProperty("bytesRemaining") long bytesRemaining ) { this.sourceServer = sourceServer; + this.status = status; this.segmentLoadsRemaining = segmentLoadsRemaining; this.segmenetsDropsRemaining = segmenetsDropsRemaining; this.bytesRemaining = bytesRemaining; - this.segmentChangesInLastRun = segmentChangesInLastRun; } @JsonProperty("sourceServer") @@ -72,10 +72,15 @@ public long getBytesRemaining() return bytesRemaining; } - @JsonProperty("segmentChangesInLastRun") - public long getSegmentChangesInLastRun() + @JsonProperty("status") + public Status getStatus() { - return segmentChangesInLastRun; + return status; + } + + public static CloneStatusMetrics unknown(String sourceServer) + { + return new CloneStatusMetrics(sourceServer, Status.TARGET_SERVER_MISSING, 0, 0, 0); } @Override @@ -91,20 +96,14 @@ public boolean equals(Object o) return segmentLoadsRemaining == that.segmentLoadsRemaining && segmenetsDropsRemaining == that.segmenetsDropsRemaining && bytesRemaining == that.bytesRemaining - && segmentChangesInLastRun == that.segmentChangesInLastRun - && Objects.equals(sourceServer, that.sourceServer); + && Objects.equals(sourceServer, that.sourceServer) + && status == that.status; } @Override public int hashCode() { - return Objects.hash( - sourceServer, - segmentLoadsRemaining, - segmenetsDropsRemaining, - bytesRemaining, - segmentChangesInLastRun - ); + return Objects.hash(sourceServer, status, segmentLoadsRemaining, segmenetsDropsRemaining, bytesRemaining); } @Override @@ -112,10 +111,17 @@ public String toString() { return "CloneStatusMetrics{" + "sourceServer='" + sourceServer + '\'' + + ", status=" + status + ", segmentLoadsRemaining=" + segmentLoadsRemaining + ", segmenetsDropsRemaining=" + segmenetsDropsRemaining + ", bytesRemaining=" + bytesRemaining + - ", segmentChangesInLastRun=" + segmentChangesInLastRun + '}'; } + + public enum Status + { + SOURCE_SERVER_MISSING, + TARGET_SERVER_MISSING, + LOADING + } } diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java index 32b20cf33759..d4338c5f44f4 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java @@ -25,6 +25,7 @@ import com.google.inject.Inject; import com.sun.jersey.spi.container.ResourceFilters; import org.apache.druid.server.coordinator.CloneStatusManager; +import org.apache.druid.server.coordinator.CloneStatusMetrics; import org.apache.druid.server.coordinator.DruidCoordinator; import org.apache.druid.server.http.security.StateResourceFilter; import org.apache.druid.timeline.DataSegment; @@ -47,13 +48,6 @@ public class CoordinatorResource private final CloneStatusManager cloneStatusManager; private final CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer; - public CoordinatorResource(DruidCoordinator coordinator) - { - this.coordinator = coordinator; - this.cloneStatusManager = null; - this.coordinatorDynamicConfigSyncer = null; - } - @Inject public CoordinatorResource(DruidCoordinator coordinator, CloneStatusManager cloneStatusManager, CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer) { @@ -184,8 +178,14 @@ public Response getBrokerStatus() @Path("/cloneStatus") @ResourceFilters(StateResourceFilter.class) @Produces(MediaType.APPLICATION_JSON) - public Response getCloneStatus() + public Response getCloneStatus(@QueryParam("targetServer") String targetServer) { - return Response.ok(cloneStatusManager.getCloneStatusMap()).build(); + if (targetServer != null) { + CloneStatusMetrics statusForServer = cloneStatusManager.getStatusForServer(targetServer); + return Response.ok(ImmutableMap.of(targetServer, statusForServer)).build(); + + } else { + return Response.ok(cloneStatusManager.getStatusForAllServers()).build(); + } } } diff --git a/server/src/test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java b/server/src/test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java index 0a34305cb382..edfe1460dc74 100644 --- a/server/src/test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java +++ b/server/src/test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java @@ -28,9 +28,9 @@ public class CloneStatusMetricsTest @Test public void testSerde() throws Exception { - CloneStatusMetrics metrics = new CloneStatusMetrics("host2", 1, 3012, 10, 100); + CloneStatusMetrics metrics = new CloneStatusMetrics("host2", CloneStatusMetrics.Status.LOADING, 3012, 10, 100); byte[] bytes = DefaultObjectMapper.INSTANCE.writeValueAsBytes(metrics); CloneStatusMetrics deserialized = DefaultObjectMapper.INSTANCE.readValue(bytes, CloneStatusMetrics.class); Assert.assertEquals(deserialized, metrics); } -} \ No newline at end of file +} diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java index fe56c5c38d1d..101841ccec56 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java @@ -58,7 +58,7 @@ public void testLeader() EasyMock.expect(mock.getCurrentLeader()).andReturn("boz").once(); EasyMock.replay(mock); - final Response response = new CoordinatorResource(mock).getLeader(); + final Response response = new CoordinatorResource(mock, null, null).getLeader(); Assert.assertEquals("boz", response.getEntity()); Assert.assertEquals(200, response.getStatus()); } @@ -71,12 +71,12 @@ public void testIsLeader() EasyMock.replay(mock); // true - final Response response1 = new CoordinatorResource(mock).isLeader(); + final Response response1 = new CoordinatorResource(mock, null, null).isLeader(); Assert.assertEquals(ImmutableMap.of("leader", true), response1.getEntity()); Assert.assertEquals(200, response1.getStatus()); // false - final Response response2 = new CoordinatorResource(mock).isLeader(); + final Response response2 = new CoordinatorResource(mock, null, null).isLeader(); Assert.assertEquals(ImmutableMap.of("leader", false), response2.getEntity()); Assert.assertEquals(404, response2.getStatus()); } @@ -89,7 +89,7 @@ public void testGetLoadStatusSimple() .once(); EasyMock.replay(mock); - final Response response = new CoordinatorResource(mock).getLoadQueue("true", null); + final Response response = new CoordinatorResource(mock, null, null).getLoadQueue("true", null); Assert.assertEquals( ImmutableMap.of( "hist1", @@ -125,7 +125,7 @@ public void testGetStatusOfDuties() ).once(); EasyMock.replay(mock); - final Response response = new CoordinatorResource(mock).getStatusOfDuties(); + final Response response = new CoordinatorResource(mock, null, null).getStatusOfDuties(); Assert.assertEquals(200, response.getStatus()); final Object payload = response.getEntity(); From 227ea1d074d87cc864cead43f577faebbbad4257 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Sat, 12 Apr 2025 20:33:06 +0530 Subject: [PATCH 11/38] Rework coordinator changes --- .../client/coordinator/CoordinatorClient.java | 4 +- .../coordinator/CloneStatusManager.java | 2 +- .../coordinator/CloneStatusMetrics.java | 4 +- .../server/coordinator/DruidCoordinator.java | 22 -------- .../duty/BrokerDynamicConfigSync.java | 2 +- .../http/CoordinatorDynamicConfigSyncer.java | 55 ++++++++++++------- .../CoordinatorDynamicConfigsResource.java | 2 +- .../coordinator/DruidCoordinatorTest.java | 21 +++++-- .../CoordinatorSimulationBuilder.java | 14 ++++- .../server/http/CoordinatorResourceTest.java | 15 +++-- 10 files changed, 80 insertions(+), 61 deletions(-) diff --git a/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClient.java b/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClient.java index 8b3ce2d0a76d..c4f112917c84 100644 --- a/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClient.java +++ b/server/src/main/java/org/apache/druid/client/coordinator/CoordinatorClient.java @@ -89,7 +89,9 @@ public interface CoordinatorClient ListenableFuture getCompactionSnapshots(@Nullable String dataSource); /** - * TODO: javadoc + * Gets the latest coordinator dynamic config. + *

+ * API: {@code GET /druid/coordinator/v1/config} */ ListenableFuture getCoordinatorDynamicConfig(); } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java index 90ec715d1ca1..1fd1e1a1acf0 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java @@ -33,7 +33,7 @@ public class CloneStatusManager public CloneStatusManager() { - this.cloneStatusSnapshot = new AtomicReference<>(ImmutableMap.of());; + this.cloneStatusSnapshot = new AtomicReference<>(ImmutableMap.of()); } public Map getStatusForAllServers() diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java index c8cb2b822eb7..dfddeb3ee0c1 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java @@ -37,7 +37,7 @@ public CloneStatusMetrics( @JsonProperty("sourceServer") String sourceServer, @JsonProperty("status") Status status, @JsonProperty("segmentLoadsRemaining") long segmentLoadsRemaining, - @JsonProperty("segmenetsDropsRemaining") long segmenetsDropsRemaining, + @JsonProperty("segmentDropsRemaining") long segmenetsDropsRemaining, @JsonProperty("bytesRemaining") long bytesRemaining ) { @@ -60,7 +60,7 @@ public long getSegmentLoadsRemaining() return segmentLoadsRemaining; } - @JsonProperty("segmenetsDropsRemaining") + @JsonProperty("segmentDropsRemaining") public long getSegmenetsDropsRemaining() { return segmenetsDropsRemaining; diff --git a/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java b/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java index 1eff7b08dc04..af0e07c99c4b 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java @@ -173,28 +173,6 @@ public class DruidCoordinator private static final String INDEXING_SERVICE_DUTIES_DUTY_GROUP = "IndexingServiceDuties"; private static final String COMPACT_SEGMENTS_DUTIES_DUTY_GROUP = "CompactSegmentsDuties"; - public DruidCoordinator( - DruidCoordinatorConfig config, - MetadataManager metadataManager, - ServerInventoryView serverInventoryView, - ServiceEmitter emitter, - ScheduledExecutorFactory scheduledExecutorFactory, - OverlordClient overlordClient, - LoadQueueTaskMaster taskMaster, - SegmentLoadQueueManager loadQueueManager, - ServiceAnnouncer serviceAnnouncer, - @Self DruidNode self, - CoordinatorCustomDutyGroups customDutyGroups, - LookupCoordinatorManager lookupCoordinatorManager, - @Coordinator DruidLeaderSelector coordLeaderSelector, - @Nullable CoordinatorSegmentMetadataCache coordinatorSegmentMetadataCache, - CentralizedDatasourceSchemaConfig centralizedDatasourceSchemaConfig, - CompactionStatusTracker compactionStatusTracker - ) - { - this(config, metadataManager, serverInventoryView, emitter, scheduledExecutorFactory, overlordClient, taskMaster, loadQueueManager, serviceAnnouncer, self, customDutyGroups, lookupCoordinatorManager, coordLeaderSelector, coordinatorSegmentMetadataCache, centralizedDatasourceSchemaConfig, compactionStatusTracker, null, null); - } - @Inject public DruidCoordinator( DruidCoordinatorConfig config, diff --git a/server/src/main/java/org/apache/druid/server/coordinator/duty/BrokerDynamicConfigSync.java b/server/src/main/java/org/apache/druid/server/coordinator/duty/BrokerDynamicConfigSync.java index 2f79442eb3ea..0e658a812064 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/duty/BrokerDynamicConfigSync.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/duty/BrokerDynamicConfigSync.java @@ -40,7 +40,7 @@ public BrokerDynamicConfigSync(CoordinatorDynamicConfigSyncer coordinatorDynamic @Override public DruidCoordinatorRuntimeParams run(DruidCoordinatorRuntimeParams params) { - coordinatorDynamicConfigSyncer.queueBroadcastConfig(); + coordinatorDynamicConfigSyncer.broadcastConfigToBrokers(); return params; } } diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java index 9dfc435820ba..a17ce7e3c68e 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java @@ -43,16 +43,17 @@ import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpResponseStatus; -import java.util.ArrayList; -import java.util.List; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicReference; +/** + * Updates all brokers with the latest coordinator dynamic config. + */ public class CoordinatorDynamicConfigSyncer { private static final Logger log = new Logger(CoordinatorDynamicConfigSyncer.class); - private static final String BROKER_UPDATE_PATH = "/druid-internal/v1/dynamicConfiguration/coordinatorDynamicConfig"; private final CoordinatorConfigManager configManager; private final ServerInventoryView serverInventoryView; @@ -61,7 +62,7 @@ public class CoordinatorDynamicConfigSyncer private final AtomicReference lastKnownConfig = new AtomicReference<>(); private final ServiceClientFactory clientFactory; private final ExecutorService exec; - private final List inSyncBrokers; + private final Set inSyncBrokers; @Inject public CoordinatorDynamicConfigSyncer( @@ -76,24 +77,23 @@ public CoordinatorDynamicConfigSyncer( this.jsonMapper = jsonMapper; this.serverInventoryView = serverInventoryView; this.exec = Execs.singleThreaded("DynamicConfigSyncer-%d"); - this.inSyncBrokers = new ArrayList<>(); // TODO: concurrency + this.inSyncBrokers = ConcurrentHashMap.newKeySet(); } - public void queueBroadcastConfig() + public void broadcastConfigToBrokers() { - final CoordinatorDynamicConfig currentDynamicConfig = configManager.getCurrentDynamicConfig(); - if (!currentDynamicConfig.equals(lastKnownConfig.get())) { - // Config has changed, clear the inSync list. - lastKnownConfig.set(currentDynamicConfig); - inSyncBrokers.clear(); + invalidateInSyncBrokersIfNeeded(); + for (DruidServerMetadata broker : getKnownBrokers()) { + exec.submit(() -> pushConfigToBroker(broker)); } + } - for (DruidServerMetadata broker : getCurrentBrokers()) { - exec.submit(() -> syncConfigToBroker(broker)); - } + public synchronized Set getInSyncBrokers() + { + return Set.copyOf(inSyncBrokers); } - private void syncConfigToBroker(DruidServerMetadata broker) + private void pushConfigToBroker(DruidServerMetadata broker) { final ServiceLocation brokerLocation = ServiceLocation.fromDruidServerMetadata(broker); final ServiceClient brokerClient = clientFactory.makeClient( @@ -103,14 +103,15 @@ private void syncConfigToBroker(DruidServerMetadata broker) ); try { + CoordinatorDynamicConfig currentDynamicConfig = configManager.getCurrentDynamicConfig(); final RequestBuilder requestBuilder = - new RequestBuilder(HttpMethod.POST, BROKER_UPDATE_PATH) - .jsonContent(jsonMapper, configManager.getCurrentDynamicConfig()); + new RequestBuilder(HttpMethod.POST, "/druid-internal/v1/dynamicConfiguration/coordinatorDynamicConfig") + .jsonContent(jsonMapper, currentDynamicConfig); final BytesFullResponseHolder responseHolder = brokerClient.request(requestBuilder, new BytesFullResponseHandler()); final HttpResponseStatus status = responseHolder.getStatus(); if (status.equals(HttpResponseStatus.OK)) { - inSyncBrokers.add(broker.getHost()); + addToInSyncBrokers(currentDynamicConfig, broker.getHost()); } else { log.error( "Received status [%s] while posting dynamic configs to broker[%s]", @@ -129,7 +130,7 @@ private void syncConfigToBroker(DruidServerMetadata broker) } } - private Set getCurrentBrokers() + private Set getKnownBrokers() { // TODO: Inventory view seems to be returning only an empty list, local work around for now. return ImmutableSet.of( @@ -140,8 +141,20 @@ private Set getCurrentBrokers() ); } - public List getInSyncBrokers() + private synchronized void invalidateInSyncBrokersIfNeeded() { - return inSyncBrokers; + final CoordinatorDynamicConfig currentDynamicConfig = configManager.getCurrentDynamicConfig(); + if (!currentDynamicConfig.equals(lastKnownConfig.get())) { + // Config has changed, clear the inSync list. + lastKnownConfig.set(currentDynamicConfig); + inSyncBrokers.clear(); + } + } + + private synchronized void addToInSyncBrokers(CoordinatorDynamicConfig config, String broker) + { + if (config.equals(lastKnownConfig.get())) { + inSyncBrokers.add(broker); + } } } diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java index 54ac5e8da016..23f857bbad61 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java @@ -87,7 +87,7 @@ public Response setDynamicConfigs( ); if (setResult.isOk()) { - coordinatorDynamicConfigSyncer.queueBroadcastConfig(); + coordinatorDynamicConfigSyncer.broadcastConfigToBrokers(); return Response.ok().build(); } else { return Response.status(Response.Status.BAD_REQUEST) diff --git a/server/src/test/java/org/apache/druid/server/coordinator/DruidCoordinatorTest.java b/server/src/test/java/org/apache/druid/server/coordinator/DruidCoordinatorTest.java index fa6a4e9bdc56..182fce84cb0c 100644 --- a/server/src/test/java/org/apache/druid/server/coordinator/DruidCoordinatorTest.java +++ b/server/src/test/java/org/apache/druid/server/coordinator/DruidCoordinatorTest.java @@ -71,6 +71,7 @@ import org.apache.druid.server.coordinator.rules.IntervalLoadRule; import org.apache.druid.server.coordinator.rules.Rule; import org.apache.druid.server.coordinator.stats.Stats; +import org.apache.druid.server.http.CoordinatorDynamicConfigSyncer; import org.apache.druid.server.lookup.cache.LookupCoordinatorManager; import org.apache.druid.timeline.DataSegment; import org.easymock.EasyMock; @@ -167,7 +168,9 @@ public void setUp() throws Exception new TestDruidLeaderSelector(), null, CentralizedDatasourceSchemaConfig.create(), - new CompactionStatusTracker(OBJECT_MAPPER) + new CompactionStatusTracker(OBJECT_MAPPER), + EasyMock.niceMock(CoordinatorDynamicConfigSyncer.class), + EasyMock.niceMock(CloneStatusManager.class) ); } @@ -476,7 +479,9 @@ public void testCompactSegmentsDutyWhenCustomDutyGroupEmpty() new TestDruidLeaderSelector(), null, CentralizedDatasourceSchemaConfig.create(), - new CompactionStatusTracker(OBJECT_MAPPER) + new CompactionStatusTracker(OBJECT_MAPPER), + EasyMock.niceMock(CoordinatorDynamicConfigSyncer.class), + EasyMock.niceMock(CloneStatusManager.class) ); coordinator.start(); @@ -526,7 +531,9 @@ public void testInitializeCompactSegmentsDutyWhenCustomDutyGroupDoesNotContainsC new TestDruidLeaderSelector(), null, CentralizedDatasourceSchemaConfig.create(), - new CompactionStatusTracker(OBJECT_MAPPER) + new CompactionStatusTracker(OBJECT_MAPPER), + EasyMock.niceMock(CoordinatorDynamicConfigSyncer.class), + EasyMock.niceMock(CloneStatusManager.class) ); coordinator.start(); // Since CompactSegments is not enabled in Custom Duty Group, then CompactSegments must be created in IndexingServiceDuties @@ -576,7 +583,9 @@ public void testInitializeCompactSegmentsDutyWhenCustomDutyGroupContainsCompactS new TestDruidLeaderSelector(), null, CentralizedDatasourceSchemaConfig.create(), - new CompactionStatusTracker(OBJECT_MAPPER) + new CompactionStatusTracker(OBJECT_MAPPER), + EasyMock.niceMock(CoordinatorDynamicConfigSyncer.class), + EasyMock.niceMock(CloneStatusManager.class) ); coordinator.start(); @@ -688,7 +697,9 @@ public void testCoordinatorCustomDutyGroupsRunAsExpected() throws Exception new TestDruidLeaderSelector(), null, CentralizedDatasourceSchemaConfig.create(), - new CompactionStatusTracker(OBJECT_MAPPER) + new CompactionStatusTracker(OBJECT_MAPPER), + EasyMock.niceMock(CoordinatorDynamicConfigSyncer.class), + EasyMock.niceMock(CloneStatusManager.class) ); coordinator.start(); diff --git a/server/src/test/java/org/apache/druid/server/coordinator/simulate/CoordinatorSimulationBuilder.java b/server/src/test/java/org/apache/druid/server/coordinator/simulate/CoordinatorSimulationBuilder.java index f8e28e4979bc..70237158a007 100644 --- a/server/src/test/java/org/apache/druid/server/coordinator/simulate/CoordinatorSimulationBuilder.java +++ b/server/src/test/java/org/apache/druid/server/coordinator/simulate/CoordinatorSimulationBuilder.java @@ -43,6 +43,7 @@ import org.apache.druid.rpc.indexing.SegmentUpdateResponse; import org.apache.druid.segment.metadata.CentralizedDatasourceSchemaConfig; import org.apache.druid.server.compaction.CompactionStatusTracker; +import org.apache.druid.server.coordinator.CloneStatusManager; import org.apache.druid.server.coordinator.CoordinatorConfigManager; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import org.apache.druid.server.coordinator.DruidCompactionConfig; @@ -63,6 +64,7 @@ import org.apache.druid.server.coordinator.loading.LoadQueueTaskMaster; import org.apache.druid.server.coordinator.loading.SegmentLoadQueueManager; import org.apache.druid.server.coordinator.rules.Rule; +import org.apache.druid.server.http.CoordinatorDynamicConfigSyncer; import org.apache.druid.server.http.SegmentsToUpdateFilter; import org.apache.druid.server.lookup.cache.LookupCoordinatorManager; import org.apache.druid.timeline.DataSegment; @@ -221,8 +223,8 @@ public CoordinatorSimulation build() null, CentralizedDatasourceSchemaConfig.create(), new CompactionStatusTracker(OBJECT_MAPPER), - null, - null + env.configSyncer, + env.cloneStatusManager ); return new SimulationImpl(coordinator, env); @@ -422,6 +424,8 @@ private static class Environment private final MetadataManager metadataManager; private final LookupCoordinatorManager lookupCoordinatorManager; private final DruidCoordinatorConfig coordinatorConfig; + private final CoordinatorDynamicConfigSyncer configSyncer; + private final CloneStatusManager cloneStatusManager; private final boolean loadImmediately; private final boolean autoSyncInventory; @@ -485,6 +489,12 @@ private Environment( null, null ); + + this.configSyncer = EasyMock.niceMock(CoordinatorDynamicConfigSyncer.class); + this.cloneStatusManager = EasyMock.niceMock(CloneStatusManager.class); + + mocks.add(configSyncer); + mocks.add(cloneStatusManager); } private void setUp() throws Exception diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java index 101841ccec56..459bb9ab2c6e 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java @@ -21,6 +21,7 @@ import com.google.common.collect.ImmutableMap; import org.apache.druid.java.util.common.DateTimes; +import org.apache.druid.server.coordinator.CloneStatusManager; import org.apache.druid.server.coordinator.DruidCoordinator; import org.apache.druid.server.coordinator.duty.DutyGroupStatus; import org.apache.druid.server.coordinator.loading.TestLoadQueuePeon; @@ -39,11 +40,15 @@ public class CoordinatorResourceTest { private DruidCoordinator mock; + private CloneStatusManager cloneStatusManager; + private CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer; @Before public void setUp() { mock = EasyMock.createStrictMock(DruidCoordinator.class); + cloneStatusManager = EasyMock.createStrictMock(CloneStatusManager.class); + coordinatorDynamicConfigSyncer = EasyMock.createStrictMock(CoordinatorDynamicConfigSyncer.class); } @After @@ -58,7 +63,7 @@ public void testLeader() EasyMock.expect(mock.getCurrentLeader()).andReturn("boz").once(); EasyMock.replay(mock); - final Response response = new CoordinatorResource(mock, null, null).getLeader(); + final Response response = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).getLeader(); Assert.assertEquals("boz", response.getEntity()); Assert.assertEquals(200, response.getStatus()); } @@ -71,12 +76,12 @@ public void testIsLeader() EasyMock.replay(mock); // true - final Response response1 = new CoordinatorResource(mock, null, null).isLeader(); + final Response response1 = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).isLeader(); Assert.assertEquals(ImmutableMap.of("leader", true), response1.getEntity()); Assert.assertEquals(200, response1.getStatus()); // false - final Response response2 = new CoordinatorResource(mock, null, null).isLeader(); + final Response response2 = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).isLeader(); Assert.assertEquals(ImmutableMap.of("leader", false), response2.getEntity()); Assert.assertEquals(404, response2.getStatus()); } @@ -89,7 +94,7 @@ public void testGetLoadStatusSimple() .once(); EasyMock.replay(mock); - final Response response = new CoordinatorResource(mock, null, null).getLoadQueue("true", null); + final Response response = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).getLoadQueue("true", null); Assert.assertEquals( ImmutableMap.of( "hist1", @@ -125,7 +130,7 @@ public void testGetStatusOfDuties() ).once(); EasyMock.replay(mock); - final Response response = new CoordinatorResource(mock, null, null).getStatusOfDuties(); + final Response response = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).getStatusOfDuties(); Assert.assertEquals(200, response.getStatus()); final Object payload = response.getEntity(); From 478ffede82799a0478b84d9da8ea28514e7eb281 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Sat, 12 Apr 2025 22:14:46 +0530 Subject: [PATCH 12/38] Cleanup --- .../client/CoordinatorDynamicConfigView.java | 18 ++++++------------ .../server/coordinator/CloneStatusManager.java | 2 +- .../duty/BrokerDynamicConfigSync.java | 3 --- .../coordinator/duty/CloneHistoricals.java | 2 +- .../client/CachingClusteredClientTest.java | 16 +++++++++++++++- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java b/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java index 9d8cbfc99742..9572eec6b2cc 100644 --- a/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java +++ b/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java @@ -65,19 +65,13 @@ public void updateCloneServers(CoordinatorDynamicConfig updatedConfig) } @LifecycleStart - public void start() throws InterruptedException + public void start() throws Exception { - log.info("Initializing dynamic configuration."); + log.info("Fetching coordinator dynamic configuration."); - try { - // TODO: handle exceptions and timeouts - CoordinatorDynamicConfig coordinatorDynamicConfig = coordinatorClient.getCoordinatorDynamicConfig().get(); - updateCloneServers(coordinatorDynamicConfig); - log.info("Synced clone servers TRUE [%s]", coordinatorDynamicConfig.getCloneServers()); - } - catch (Exception e) { - log.error(e, "Exception"); - throw new RuntimeException(e); - } + CoordinatorDynamicConfig coordinatorDynamicConfig = coordinatorClient.getCoordinatorDynamicConfig().get(); + updateCloneServers(coordinatorDynamicConfig); + + log.info("Successfully initialized dynamic config: [%s]", coordinatorDynamicConfig); } } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java index 1fd1e1a1acf0..b0015ba09afb 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java @@ -63,8 +63,8 @@ public void updateStats(Map historicalMap, Map getTargetCloneServers() + { + return ImmutableSet.of(); + } + + @Override + public Set getSourceClusterServers() + { + return ImmutableSet.of(); + } + } ); } From 76be7b561da3467607dcceb5141c0af244a504b5 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Mon, 14 Apr 2025 11:16:24 +0530 Subject: [PATCH 13/38] Update with node discovery --- .../druid/discovery/DiscoveryDruidNode.java | 16 ++++++++ .../http/CoordinatorDynamicConfigSyncer.java | 38 +++++++++---------- .../org/apache/druid/cli/CliCoordinator.java | 2 +- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/server/src/main/java/org/apache/druid/discovery/DiscoveryDruidNode.java b/server/src/main/java/org/apache/druid/discovery/DiscoveryDruidNode.java index 3a62e5344b11..36ea317215b0 100644 --- a/server/src/main/java/org/apache/druid/discovery/DiscoveryDruidNode.java +++ b/server/src/main/java/org/apache/druid/discovery/DiscoveryDruidNode.java @@ -31,6 +31,7 @@ import org.apache.druid.java.util.common.IAE; import org.apache.druid.java.util.common.NonnullPair; import org.apache.druid.java.util.common.logger.Logger; +import org.apache.druid.rpc.ServiceLocation; import org.apache.druid.server.DruidNode; import org.joda.time.DateTime; @@ -200,6 +201,21 @@ public T getService(String key, Class clazz) return null; } + public ServiceLocation toServiceLocation() + { + final DruidNode druidNode = getDruidNode(); + if (druidNode == null) { + return null; + } + + return new ServiceLocation( + druidNode.getHost(), + druidNode.getPlaintextPort(), + druidNode.getTlsPort(), + "" + ); + } + public DruidServer toDruidServer() { final DataNodeService dataNodeService = getService( diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java index a17ce7e3c68e..a24460128cb4 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java @@ -20,9 +20,9 @@ package org.apache.druid.server.http; import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.collect.ImmutableSet; import com.google.inject.Inject; -import org.apache.druid.client.ServerInventoryView; +import org.apache.druid.discovery.DiscoveryDruidNode; +import org.apache.druid.discovery.DruidNodeDiscoveryProvider; import org.apache.druid.discovery.NodeRole; import org.apache.druid.guice.annotations.EscalatedGlobal; import org.apache.druid.guice.annotations.Json; @@ -36,8 +36,6 @@ import org.apache.druid.rpc.ServiceClientFactory; import org.apache.druid.rpc.ServiceLocation; import org.apache.druid.rpc.StandardRetryPolicy; -import org.apache.druid.server.coordination.DruidServerMetadata; -import org.apache.druid.server.coordination.ServerType; import org.apache.druid.server.coordinator.CoordinatorConfigManager; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import org.jboss.netty.handler.codec.http.HttpMethod; @@ -47,6 +45,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; /** * Updates all brokers with the latest coordinator dynamic config. @@ -56,8 +55,8 @@ public class CoordinatorDynamicConfigSyncer private static final Logger log = new Logger(CoordinatorDynamicConfigSyncer.class); private final CoordinatorConfigManager configManager; - private final ServerInventoryView serverInventoryView; private final ObjectMapper jsonMapper; + private final DruidNodeDiscoveryProvider druidNodeDiscovery; private final AtomicReference lastKnownConfig = new AtomicReference<>(); private final ServiceClientFactory clientFactory; @@ -69,13 +68,13 @@ public CoordinatorDynamicConfigSyncer( @EscalatedGlobal final ServiceClientFactory clientFactory, final CoordinatorConfigManager configManager, @Json final ObjectMapper jsonMapper, - final ServerInventoryView serverInventoryView + final DruidNodeDiscoveryProvider druidNodeDiscoveryProvider ) { this.clientFactory = clientFactory; this.configManager = configManager; this.jsonMapper = jsonMapper; - this.serverInventoryView = serverInventoryView; + this.druidNodeDiscovery = druidNodeDiscoveryProvider; this.exec = Execs.singleThreaded("DynamicConfigSyncer-%d"); this.inSyncBrokers = ConcurrentHashMap.newKeySet(); } @@ -83,7 +82,7 @@ public CoordinatorDynamicConfigSyncer( public void broadcastConfigToBrokers() { invalidateInSyncBrokersIfNeeded(); - for (DruidServerMetadata broker : getKnownBrokers()) { + for (ServiceLocation broker : getKnownBrokers()) { exec.submit(() -> pushConfigToBroker(broker)); } } @@ -93,9 +92,8 @@ public synchronized Set getInSyncBrokers() return Set.copyOf(inSyncBrokers); } - private void pushConfigToBroker(DruidServerMetadata broker) + private void pushConfigToBroker(ServiceLocation brokerLocation) { - final ServiceLocation brokerLocation = ServiceLocation.fromDruidServerMetadata(broker); final ServiceClient brokerClient = clientFactory.makeClient( NodeRole.BROKER.getJsonName(), new FixedServiceLocator(brokerLocation), @@ -111,12 +109,12 @@ private void pushConfigToBroker(DruidServerMetadata broker) final BytesFullResponseHolder responseHolder = brokerClient.request(requestBuilder, new BytesFullResponseHandler()); final HttpResponseStatus status = responseHolder.getStatus(); if (status.equals(HttpResponseStatus.OK)) { - addToInSyncBrokers(currentDynamicConfig, broker.getHost()); + addToInSyncBrokers(currentDynamicConfig, brokerLocation.getHost()); } else { log.error( "Received status [%s] while posting dynamic configs to broker[%s]", status.getCode(), - broker.getHostAndPort() + brokerLocation ); } } @@ -125,20 +123,18 @@ private void pushConfigToBroker(DruidServerMetadata broker) log.error( e, "Exception while syncing dynamic configuration to broker[%s]", - broker.getHostAndPort() + brokerLocation ); } } - private Set getKnownBrokers() + private Set getKnownBrokers() { - // TODO: Inventory view seems to be returning only an empty list, local work around for now. - return ImmutableSet.of( - new DruidServerMetadata( - "localhost:8082", - "localhost:8082", - null, 0, ServerType.BROKER, "tier1", 0) - ); + return druidNodeDiscovery.getForNodeRole(NodeRole.BROKER) + .getAllNodes() + .stream() + .map(DiscoveryDruidNode::toServiceLocation) + .collect(Collectors.toSet()); } private synchronized void invalidateInSyncBrokersIfNeeded() diff --git a/services/src/main/java/org/apache/druid/cli/CliCoordinator.java b/services/src/main/java/org/apache/druid/cli/CliCoordinator.java index 67e4c3aa0046..993f3f7bf4c1 100644 --- a/services/src/main/java/org/apache/druid/cli/CliCoordinator.java +++ b/services/src/main/java/org/apache/druid/cli/CliCoordinator.java @@ -113,11 +113,11 @@ import org.apache.druid.server.http.ClusterResource; import org.apache.druid.server.http.CoordinatorCompactionConfigsResource; import org.apache.druid.server.http.CoordinatorCompactionResource; +import org.apache.druid.server.http.CoordinatorDynamicConfigSyncer; import org.apache.druid.server.http.CoordinatorDynamicConfigsResource; import org.apache.druid.server.http.CoordinatorRedirectInfo; import org.apache.druid.server.http.CoordinatorResource; import org.apache.druid.server.http.DataSourcesResource; -import org.apache.druid.server.http.CoordinatorDynamicConfigSyncer; import org.apache.druid.server.http.IntervalsResource; import org.apache.druid.server.http.LookupCoordinatorResource; import org.apache.druid.server.http.MetadataResource; From b1f7e0008fd650c0e6dbca5c2911297fd045f4b8 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Mon, 14 Apr 2025 12:10:03 +0530 Subject: [PATCH 14/38] Tests --- .../coordinator/CoordinatorDynamicConfig.java | 4 ++ .../coordinator/CloneStatusMetricsTest.java | 10 +++++ .../http/CoordinatorDynamicConfigTest.java | 10 +++++ .../server/http/CoordinatorResourceTest.java | 40 +++++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java b/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java index 69ffd24161c8..f34c3b8ae39e 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java @@ -394,6 +394,7 @@ public boolean equals(Object o) && replicateAfterLoadTimeout == that.replicateAfterLoadTimeout && maxSegmentsInNodeLoadingQueue == that.maxSegmentsInNodeLoadingQueue && useRoundRobinSegmentAssignment == that.useRoundRobinSegmentAssignment + && smartSegmentLoading == that.smartSegmentLoading && pauseCoordination == that.pauseCoordination && Objects.equals( specificDataSourcesToKillUnusedSegmentsIn, @@ -419,6 +420,9 @@ public int hashCode() replicationThrottleLimit, balancerComputeThreads, maxSegmentsInNodeLoadingQueue, + useRoundRobinSegmentAssignment, + smartSegmentLoading, + replicateAfterLoadTimeout, specificDataSourcesToKillUnusedSegmentsIn, killTaskSlotRatio, maxKillTaskSlots, diff --git a/server/src/test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java b/server/src/test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java index edfe1460dc74..e9752ab07e3c 100644 --- a/server/src/test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java +++ b/server/src/test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java @@ -19,6 +19,7 @@ package org.apache.druid.server.coordinator; +import nl.jqno.equalsverifier.EqualsVerifier; import org.apache.druid.jackson.DefaultObjectMapper; import org.junit.Assert; import org.junit.Test; @@ -33,4 +34,13 @@ public void testSerde() throws Exception CloneStatusMetrics deserialized = DefaultObjectMapper.INSTANCE.readValue(bytes, CloneStatusMetrics.class); Assert.assertEquals(deserialized, metrics); } + + @Test + public void testEquals() + { + EqualsVerifier.forClass(CloneStatusMetrics.class) + .withNonnullFields("sourceServer", "status") + .usingGetClass() + .verify(); + } } diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java index 0aa43a42ec8f..22f3ccbdd4db 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import nl.jqno.equalsverifier.EqualsVerifier; import org.apache.druid.segment.TestHelper; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import org.apache.druid.utils.JvmUtils; @@ -643,4 +644,13 @@ private static int getDefaultNumBalancerThreads() { return Math.max(1, JvmUtils.getRuntimeInfo().getAvailableProcessors() / 2); } + + @Test + public void testEquals() + { + EqualsVerifier.forClass(CoordinatorDynamicConfig.class) + .withIgnoredFields("validDebugDimensions") + .usingGetClass() + .verify(); + } } diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java index 459bb9ab2c6e..cf84b5188fd5 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableMap; import org.apache.druid.java.util.common.DateTimes; import org.apache.druid.server.coordinator.CloneStatusManager; +import org.apache.druid.server.coordinator.CloneStatusMetrics; import org.apache.druid.server.coordinator.DruidCoordinator; import org.apache.druid.server.coordinator.duty.DutyGroupStatus; import org.apache.druid.server.coordinator.loading.TestLoadQueuePeon; @@ -36,6 +37,8 @@ import javax.ws.rs.core.Response; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; public class CoordinatorResourceTest { @@ -151,4 +154,41 @@ public void testGetStatusOfDuties() Assert.assertEquals(100L, observedStatus.getAvgRuntimeMillis()); Assert.assertEquals(500L, observedStatus.getAvgRunGapMillis()); } + + @Test + public void testGetBrokerStatus() + { + EasyMock.expect(coordinatorDynamicConfigSyncer.getInSyncBrokers()).andReturn(Set.of("brok1")).once(); + EasyMock.replay(mock); + EasyMock.replay(coordinatorDynamicConfigSyncer); + EasyMock.replay(cloneStatusManager); + + final Response response = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).getBrokerStatus(); + Assert.assertEquals(200, response.getStatus()); + + Assert.assertEquals(Set.of("brok1"), response.getEntity()); + } + + @Test + public void testGetCloneStatus() + { + Map statusMetrics = ImmutableMap.of( + "hist1", new CloneStatusMetrics("hist3", CloneStatusMetrics.Status.LOADING, 2, 0, 1000), + "hist2", CloneStatusMetrics.unknown("hist4") + ); + + EasyMock.expect(cloneStatusManager.getStatusForAllServers()).andReturn(statusMetrics).once(); + EasyMock.expect(cloneStatusManager.getStatusForServer("hist2")).andReturn(CloneStatusMetrics.unknown("hist4")).once(); + EasyMock.replay(mock); + EasyMock.replay(coordinatorDynamicConfigSyncer); + EasyMock.replay(cloneStatusManager); + + Response response = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).getCloneStatus(null); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals(statusMetrics, response.getEntity()); + + response = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).getCloneStatus("hist2"); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals(Map.of("hist2", CloneStatusMetrics.unknown("hist4")), response.getEntity()); + } } From 4acf4b7c3ae05b396b53f4bd1e0cbd9e4008e7b9 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Tue, 15 Apr 2025 09:32:23 +0530 Subject: [PATCH 15/38] Add docs --- docs/api-reference/service-status-api.md | 124 ++++++++++++++++++++++- docs/querying/query-context.md | 1 + 2 files changed, 124 insertions(+), 1 deletion(-) diff --git a/docs/api-reference/service-status-api.md b/docs/api-reference/service-status-api.md index 6e801ae632e1..da440582363e 100644 --- a/docs/api-reference/service-status-api.md +++ b/docs/api-reference/service-status-api.md @@ -1334,4 +1334,126 @@ Host: http://BROKER_IP:BROKER_PORT #### Sample response -A successful response to this endpoint results in an empty response body. \ No newline at end of file +A successful response to this endpoint results in an empty response body. + +### Get Historical Cloning Status + +Retrieves the current status of Historical cloning. + +#### URL + +`GET` `/druid/coordinator/v1/cloneStatus` + +#### Responses + + + + + + +
+ +*Successfully retrieved cloning status* + +
+
+ +#### Sample request + + + + + + +```shell +curl "http://COORDINATOR_IP:COORDINATOR_PORT/druid/coordinator/v1/cloneStatus" +``` + + + + + +```http +GET /druid/coordinator/v1/cloneStatus HTTP/1.1 +Host: http://COORDINATOR_IP:COORDINATOR_PORT +``` + + + + +#### Sample response + +

+ View the response + +```json +{ + "localhost:8083": { + "sourceServer": "localhost:8089", + "status": "LOADING", + "segmentLoadsRemaining": 0, + "segmenetsDropsRemaining": 0, + "bytesRemaining": 0 + } +} +``` + +
+ +### Get Broker dynamic configuration view + +Retrieves the list of Brokers which have an up-to-date view of Coordinator dynamic configuration. + +#### URL + +`GET` `/druid/coordinator/v1/brokerConfigurationStatus` + +#### Responses + + + + + + +
+ +*Successfully retrieved Broker Configuration view* + +
+
+ +#### Sample request + + + + + + +```shell +curl "http://COORDINATOR_IP:COORDINATOR_PORT/druid/coordinator/v1/brokerConfigurationStatus" +``` + + + + + +```http +GET /druid/coordinator/v1/brokerConfigurationStatus HTTP/1.1 +Host: http://COORDINATOR_IP:COORDINATOR_PORT +``` + + + + +#### Sample response + +
+ View the response + +```json +[ + "localhost:8082" +] +``` + +
diff --git a/docs/querying/query-context.md b/docs/querying/query-context.md index f62c7f8334f6..e867e6d8f162 100644 --- a/docs/querying/query-context.md +++ b/docs/querying/query-context.md @@ -66,6 +66,7 @@ See [SQL query context](sql-query-context.md) for other query context parameters |`debug`| `false` | Flag indicating whether to enable debugging outputs for the query. When set to false, no additional logs will be produced (logs produced will be entirely dependent on your logging level). When set to true, the following addition logs will be produced:
- Log the stack trace of the exception (if any) produced by the query | |`setProcessingThreadNames`|`true`| Whether processing thread names will be set to `queryType_dataSource_intervals` while processing a query. This aids in interpreting thread dumps, and is on by default. Query overhead can be reduced slightly by setting this to `false`. This has a tiny effect in most scenarios, but can be meaningful in high-QPS, low-per-segment-processing-time scenarios. | |`sqlPlannerBloat`|`1000`|Calcite parameter which controls whether to merge two Project operators when inlining expressions causes complexity to increase. Implemented as a workaround to exception `There are not enough rules to produce a node with desired properties: convention=DRUID, sort=[]` thrown after rejecting the merge of two projects.| +|`cloneQueryMode`|`EXCLUDE`| Indicates whether clone Historicals should be queried by brokers. Clone servers are created by the `cloneServers` Coordinator dynamic configuration. Possible values are `EXCLUDE`, `INCLUDE` and `ONLY`. `EXCLUDE` means that clone Historicals are not queried by the broker. `ONLY` indicates that when given a choice between the clone Historical and the original Historical which is being cloned, the broker chooses the clones; Historicals which are not involved in the cloning process will still be queried. `INCLUDE` means that broker queries any Historical without regarding clone status. | ## Parameters by query type From 3e8b32e65ebe32e5c8070e5c7a532b9d58890c93 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Tue, 15 Apr 2025 13:43:16 +0530 Subject: [PATCH 16/38] Fix Benchmarks --- .../CachingClusteredClientBenchmark.java | 68 +++++++++++++++---- .../client/selector/HistoricalFilter.java | 2 +- .../server/ClientQuerySegmentWalker.java | 4 +- 3 files changed, 56 insertions(+), 18 deletions(-) diff --git a/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java b/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java index 030441aee937..e85f299549cf 100644 --- a/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java +++ b/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java @@ -28,6 +28,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Ordering; import org.apache.druid.client.CachingClusteredClient; +import org.apache.druid.client.CoordinatorDynamicConfigView; import org.apache.druid.client.DruidServer; import org.apache.druid.client.ImmutableDruidServer; import org.apache.druid.client.QueryableDruidServer; @@ -53,6 +54,7 @@ import org.apache.druid.java.util.common.io.Closer; import org.apache.druid.java.util.common.logger.Logger; import org.apache.druid.math.expr.ExprMacroTable; +import org.apache.druid.query.BaseQuery; import org.apache.druid.query.BrokerParallelMergeConfig; import org.apache.druid.query.BySegmentQueryRunner; import org.apache.druid.query.DefaultQueryRunnerFactoryConglomerate; @@ -100,7 +102,9 @@ import org.apache.druid.segment.generator.GeneratorBasicSchemas; import org.apache.druid.segment.generator.GeneratorSchemaInfo; import org.apache.druid.segment.generator.SegmentGenerator; +import org.apache.druid.server.ClientQuerySegmentWalker; import org.apache.druid.server.QueryStackTests; +import org.apache.druid.server.ResourceIdPopulatingQueryRunner; import org.apache.druid.server.coordination.ServerType; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.timeline.DataSegment; @@ -132,6 +136,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Optional; +import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.ForkJoinPool; @@ -318,7 +323,20 @@ public boolean useParallelMergePool() forkJoinPool, QueryStackTests.DEFAULT_NOOP_SCHEDULER, new NoopServiceEmitter(), - null + new CoordinatorDynamicConfigView(null) + { + @Override + public Set getTargetCloneServers() + { + return Set.of(); + } + + @Override + public Set getSourceClusterServers() + { + return Set.of(); + } + } ); } @@ -369,18 +387,21 @@ public void tearDown() throws IOException @OutputTimeUnit(TimeUnit.MICROSECONDS) public void timeseriesQuery(Blackhole blackhole) { - query = Druids.newTimeseriesQueryBuilder() - .dataSource(DATA_SOURCE) - .intervals(basicSchemaIntervalSpec) - .aggregators(new LongSumAggregatorFactory("sumLongSequential", "sumLongSequential")) - .granularity(Granularity.fromString(queryGranularity)) - .context( - ImmutableMap.of( - QueryContexts.BROKER_PARALLEL_MERGE_KEY, parallelCombine, - QueryContexts.BROKER_PARALLELISM, parallelism - ) - ) - .build(); + Query q = Druids.newTimeseriesQueryBuilder() + .dataSource(DATA_SOURCE) + .intervals(basicSchemaIntervalSpec) + .aggregators(new LongSumAggregatorFactory("sumLongSequential", "sumLongSequential")) + .granularity(Granularity.fromString(queryGranularity)) + .context( + ImmutableMap.of( + BaseQuery.QUERY_ID, "BenchmarkQuery", + QueryContexts.BROKER_PARALLEL_MERGE_KEY, parallelCombine, + QueryContexts.BROKER_PARALLELISM, parallelism + ) + ) + .build(); + + query = prepareQuery(q); final List> results = runQuery(); @@ -394,7 +415,7 @@ public void timeseriesQuery(Blackhole blackhole) @OutputTimeUnit(TimeUnit.MICROSECONDS) public void topNQuery(Blackhole blackhole) { - query = new TopNQueryBuilder() + Query q = new TopNQueryBuilder() .dataSource(DATA_SOURCE) .intervals(basicSchemaIntervalSpec) .dimension(new DefaultDimensionSpec("dimZipf", null)) @@ -404,12 +425,15 @@ public void topNQuery(Blackhole blackhole) .threshold(10_000) // we are primarily measuring 'broker' merge time, so collect a significant number of results .context( ImmutableMap.of( + BaseQuery.QUERY_ID, "BenchmarkQuery", QueryContexts.BROKER_PARALLEL_MERGE_KEY, parallelCombine, QueryContexts.BROKER_PARALLELISM, parallelism ) ) .build(); + query = prepareQuery(q); + final List> results = runQuery(); for (Result result : results) { @@ -422,7 +446,7 @@ public void topNQuery(Blackhole blackhole) @OutputTimeUnit(TimeUnit.MICROSECONDS) public void groupByQuery(Blackhole blackhole) { - query = GroupByQuery + Query q = GroupByQuery .builder() .setDataSource(DATA_SOURCE) .setQuerySegmentSpec(basicSchemaIntervalSpec) @@ -434,12 +458,15 @@ public void groupByQuery(Blackhole blackhole) .setGranularity(Granularity.fromString(queryGranularity)) .setContext( ImmutableMap.of( + BaseQuery.QUERY_ID, "BenchmarkQuery", QueryContexts.BROKER_PARALLEL_MERGE_KEY, parallelCombine, QueryContexts.BROKER_PARALLELISM, parallelism ) ) .build(); + query = prepareQuery(q); + final List results = runQuery(); for (ResultRow result : results) { @@ -447,6 +474,17 @@ public void groupByQuery(Blackhole blackhole) } } + private Query prepareQuery(Query query) + { + return ResourceIdPopulatingQueryRunner.populateResourceId(query) + .withDataSource(ClientQuerySegmentWalker.generateSubqueryIds( + query.getDataSource(), + query.getId(), + query.getSqlQueryId(), + query.context().getString(QueryContexts.QUERY_RESOURCE_ID) + )); + } + private List runQuery() { //noinspection unchecked diff --git a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java index 89bcd6b5087e..01dee007b04a 100644 --- a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java +++ b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java @@ -30,7 +30,7 @@ public class HistoricalFilter implements Function>, Int2ObjectRBTreeMap>> { - public static HistoricalFilter IDENTITIY_FILTER = new HistoricalFilter(ImmutableSet::of); + public static final HistoricalFilter IDENTITIY_FILTER = new HistoricalFilter(ImmutableSet::of); public HistoricalFilter(Supplier> serversToIgnoreSupplier) { diff --git a/server/src/main/java/org/apache/druid/server/ClientQuerySegmentWalker.java b/server/src/main/java/org/apache/druid/server/ClientQuerySegmentWalker.java index 1b76660ed0be..260e1c40319b 100644 --- a/server/src/main/java/org/apache/druid/server/ClientQuerySegmentWalker.java +++ b/server/src/main/java/org/apache/druid/server/ClientQuerySegmentWalker.java @@ -607,7 +607,7 @@ private QueryRunner decorateClusterRunner(Query query, QueryRunner * @param parentQueryResourceId Parent Query's Query Resource ID * @return DataSource populated with the subqueries */ - private DataSource generateSubqueryIds( + public static DataSource generateSubqueryIds( DataSource rootDataSource, @Nullable final String parentQueryId, @Nullable final String parentSqlQueryId, @@ -654,7 +654,7 @@ private DataSource generateSubqueryIds( * @param parentQueryResourceId Parent query's resource Id * @return Populates the subqueries from the map */ - private DataSource insertSubqueryIds( + private static DataSource insertSubqueryIds( DataSource currentDataSource, Map> queryDataSourceToSubqueryIds, @Nullable final String parentQueryId, From 91b0bab3380f604c61172fc83658b503cce67945 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Tue, 15 Apr 2025 16:38:18 +0530 Subject: [PATCH 17/38] Fix broker string --- .../server/http/CoordinatorDynamicConfigSyncer.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java index a24460128cb4..e0debe08b0a7 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java @@ -26,6 +26,7 @@ import org.apache.druid.discovery.NodeRole; import org.apache.druid.guice.annotations.EscalatedGlobal; import org.apache.druid.guice.annotations.Json; +import org.apache.druid.java.util.common.StringUtils; import org.apache.druid.java.util.common.concurrent.Execs; import org.apache.druid.java.util.common.logger.Logger; import org.apache.druid.java.util.http.client.response.BytesFullResponseHandler; @@ -41,6 +42,7 @@ import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpResponseStatus; +import java.net.URL; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; @@ -109,7 +111,7 @@ private void pushConfigToBroker(ServiceLocation brokerLocation) final BytesFullResponseHolder responseHolder = brokerClient.request(requestBuilder, new BytesFullResponseHandler()); final HttpResponseStatus status = responseHolder.getStatus(); if (status.equals(HttpResponseStatus.OK)) { - addToInSyncBrokers(currentDynamicConfig, brokerLocation.getHost()); + addToInSyncBrokers(currentDynamicConfig, brokerLocation); } else { log.error( "Received status [%s] while posting dynamic configs to broker[%s]", @@ -147,10 +149,11 @@ private synchronized void invalidateInSyncBrokersIfNeeded() } } - private synchronized void addToInSyncBrokers(CoordinatorDynamicConfig config, String broker) + private synchronized void addToInSyncBrokers(CoordinatorDynamicConfig config, ServiceLocation broker) { + final URL url = broker.toURL(""); if (config.equals(lastKnownConfig.get())) { - inSyncBrokers.add(broker); + inSyncBrokers.add(StringUtils.format("%s:%s", url.getHost(), url.getPort())); } } } From be8568ee3c926de2e8b81fbdf08e2d380f866f3a Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Tue, 15 Apr 2025 20:46:29 +0530 Subject: [PATCH 18/38] Cleanup --- .../controller/DartTableInputSpecSlicer.java | 5 +- .../druid/client/CachingClusteredClient.java | 60 ++++--------------- .../apache/druid/client/ServerViewUtil.java | 11 ++-- .../client/selector/HistoricalFilter.java | 27 ++++++++- .../druid/client/selector/ServerSelector.java | 16 ----- .../druid/server/BrokerQueryResource.java | 13 +++- .../druid/server/ClientInfoResource.java | 12 +++- .../druid/client/BrokerServerViewTest.java | 17 +++--- ...ingClusteredClientCacheKeyManagerTest.java | 25 ++++---- .../druid/client/DirectDruidClientTest.java | 3 +- ...ectionCountServerSelectorStrategyTest.java | 4 +- .../selector/TierSelectorStrategyTest.java | 8 +-- .../druid/server/ClientInfoResourceTest.java | 1 + 13 files changed, 101 insertions(+), 101 deletions(-) diff --git a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java index f276caa435e6..86ba4b80f892 100644 --- a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java +++ b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java @@ -25,6 +25,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import org.apache.druid.client.QueryableDruidServer; import org.apache.druid.client.TimelineServerView; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.java.util.common.ISE; import org.apache.druid.java.util.common.JodaUtils; @@ -162,7 +163,7 @@ public List sliceDynamic( */ int findWorkerForServerSelector(final ServerSelector serverSelector, final int maxNumSlices) { - final QueryableDruidServer server = serverSelector.pick(null); + final QueryableDruidServer server = serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER); if (server == null) { return UNKNOWN; @@ -279,7 +280,7 @@ static boolean shouldIncludeSegment(final ServerSelector serverSelector) int numRealtimeServers = 0; int numOtherServers = 0; - for (final DruidServerMetadata server : serverSelector.getAllServers()) { + for (final DruidServerMetadata server : serverSelector.getAllServers(HistoricalFilter.IDENTITY_FILTER)) { if (SegmentSource.REALTIME.getUsedServerTypes().contains(server.getType())) { numRealtimeServers++; } else { diff --git a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java index 9ae65dd4e1d0..1d21d8ff57a9 100644 --- a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java +++ b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java @@ -58,7 +58,6 @@ import org.apache.druid.query.BrokerParallelMergeConfig; import org.apache.druid.query.BySegmentResultValueClass; import org.apache.druid.query.CacheStrategy; -import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.Queries; import org.apache.druid.query.Query; import org.apache.druid.query.QueryContext; @@ -94,7 +93,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; @@ -106,7 +104,6 @@ import java.util.TreeMap; import java.util.concurrent.ForkJoinPool; import java.util.function.BinaryOperator; -import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.stream.Collectors; @@ -351,13 +348,17 @@ ClusterQueryResult run( } final Set segmentServers = computeSegmentsToQuery(timeline, specificSegments); + final HistoricalFilter historicalFilter = new HistoricalFilter( + coordinatorDynamicConfigView, + query.context().getCloneQueryMode() + ); @Nullable final byte[] queryCacheKey = cacheKeyManager.computeSegmentLevelQueryCacheKey(); @Nullable final String prevEtag = (String) query.getContext().get(QueryResource.HEADER_IF_NONE_MATCH); if (prevEtag != null) { @Nullable - final String currentEtag = cacheKeyManager.computeResultLevelCachingEtag(segmentServers, queryCacheKey); + final String currentEtag = cacheKeyManager.computeResultLevelCachingEtag(segmentServers, historicalFilter, queryCacheKey); if (null != currentEtag) { responseContext.putEntityTag(currentEtag); } @@ -374,7 +375,7 @@ ClusterQueryResult run( queryPlus = queryPlus.withQueryMetrics(toolChest); queryPlus.getQueryMetrics().reportQueriedSegmentCount(segmentServers.size()).emit(emitter); - final SortedMap> segmentsByServer = groupSegmentsByServer(segmentServers); + final SortedMap> segmentsByServer = groupSegmentsByServer(segmentServers, historicalFilter); LazySequence mergedResultSequence = new LazySequence<>(() -> { List> sequencesByInterval = new ArrayList<>(alreadyCachedResults.size() + segmentsByServer.size()); addSequencesFromCache(sequencesByInterval, alreadyCachedResults); @@ -602,32 +603,15 @@ private Cache.NamedKey getCachePopulatorKey(String segmentId, Interval segmentIn return cachePopulatorKeyMap.get(StringUtils.format("%s_%s", segmentId, segmentInterval)); } - private SortedMap> groupSegmentsByServer(Set segments) + private SortedMap> groupSegmentsByServer( + Set segments, + HistoricalFilter historicalFilter + ) { final SortedMap> serverSegments = new TreeMap<>(); for (SegmentServerSelector segmentServer : segments) { - Supplier> supplier = () -> { - CloneQueryMode cloneQueryMode = query.context().getCloneQueryMode(); - final Set serversToIgnore = new HashSet<>(); - - switch (cloneQueryMode) { - case ONLY: - // Remove clone sources, so that targets are queried. - serversToIgnore.addAll(coordinatorDynamicConfigView.getSourceClusterServers()); - break; - case EXCLUDE: - // Remove clone sources, so that targets are queried. - serversToIgnore.addAll(coordinatorDynamicConfigView.getTargetCloneServers()); - break; - case INCLUDE: - // Don't remove either - break; - } - return serversToIgnore; - }; - final QueryableDruidServer queryableDruidServer = segmentServer.getServer() - .pick(query, new HistoricalFilter(supplier)); + .pick(query, historicalFilter); if (queryableDruidServer == null) { log.makeAlert( @@ -842,32 +826,14 @@ byte[] computeSegmentLevelQueryCacheKey() @Nullable String computeResultLevelCachingEtag( final Set segments, + final HistoricalFilter historicalFilter, @Nullable byte[] queryCacheKey ) { Hasher hasher = Hashing.sha1().newHasher(); boolean hasOnlyHistoricalSegments = true; for (SegmentServerSelector p : segments) { - Supplier> supplier = () -> { - CloneQueryMode cloneQueryMode = query.context().getCloneQueryMode(); - final Set serversToIgnore = new HashSet<>(); - - switch (cloneQueryMode) { - case ONLY: - // Remove clone sources, so that targets are queried. - serversToIgnore.addAll(coordinatorDynamicConfigView.getSourceClusterServers()); - break; - case EXCLUDE: - // Remove clone sources, so that targets are queried. - serversToIgnore.addAll(coordinatorDynamicConfigView.getTargetCloneServers()); - break; - case INCLUDE: - // Don't remove either - break; - } - return serversToIgnore; - }; - QueryableDruidServer queryableServer = p.getServer().pick(query, new HistoricalFilter(supplier)); + QueryableDruidServer queryableServer = p.getServer().pick(query, historicalFilter); if (queryableServer == null || !queryableServer.getServer().isSegmentReplicationTarget()) { hasOnlyHistoricalSegments = false; break; diff --git a/server/src/main/java/org/apache/druid/client/ServerViewUtil.java b/server/src/main/java/org/apache/druid/client/ServerViewUtil.java index 914d51459d70..4e8584ee06d3 100644 --- a/server/src/main/java/org/apache/druid/client/ServerViewUtil.java +++ b/server/src/main/java/org/apache/druid/client/ServerViewUtil.java @@ -19,6 +19,7 @@ package org.apache.druid.client; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.query.LocatedSegmentDescriptor; import org.apache.druid.query.SegmentDescriptor; @@ -42,17 +43,19 @@ public static List getTargetLocations( TimelineServerView serverView, String datasource, List intervals, - int numCandidates + int numCandidates, + HistoricalFilter historicalFilter ) { - return getTargetLocations(serverView, new TableDataSource(datasource), intervals, numCandidates); + return getTargetLocations(serverView, new TableDataSource(datasource), intervals, numCandidates, historicalFilter); } public static List getTargetLocations( TimelineServerView serverView, TableDataSource datasource, List intervals, - int numCandidates + int numCandidates, + HistoricalFilter historicalFilter ) { final Optional> maybeTimeline = serverView.getTimeline(datasource); @@ -68,7 +71,7 @@ public static List getTargetLocations( holder.getInterval(), holder.getVersion(), chunk.getChunkNumber() ); long size = selector.getSegment().getSize(); - List candidates = selector.getCandidates(numCandidates); + List candidates = selector.getCandidates(numCandidates, historicalFilter); located.add(new LocatedSegmentDescriptor(descriptor, size, candidates)); } } diff --git a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java index 01dee007b04a..70042512dc62 100644 --- a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java +++ b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java @@ -21,8 +21,11 @@ import com.google.common.collect.ImmutableSet; import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap; +import org.apache.druid.client.CoordinatorDynamicConfigView; import org.apache.druid.client.QueryableDruidServer; +import org.apache.druid.query.CloneQueryMode; +import java.util.HashSet; import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; @@ -30,13 +33,35 @@ public class HistoricalFilter implements Function>, Int2ObjectRBTreeMap>> { - public static final HistoricalFilter IDENTITIY_FILTER = new HistoricalFilter(ImmutableSet::of); + public static final HistoricalFilter IDENTITY_FILTER = new HistoricalFilter(ImmutableSet::of); public HistoricalFilter(Supplier> serversToIgnoreSupplier) { this.serversToIgnoreSupplier = serversToIgnoreSupplier; } + public HistoricalFilter(CoordinatorDynamicConfigView configView, CloneQueryMode cloneQueryMode) + { + this.serversToIgnoreSupplier = () -> { + final Set serversToIgnore = new HashSet<>(); + + switch (cloneQueryMode) { + case ONLY: + // Remove clone sources, so that targets are queried. + serversToIgnore.addAll(configView.getSourceClusterServers()); + break; + case EXCLUDE: + // Remove clone sources, so that targets are queried. + serversToIgnore.addAll(configView.getTargetCloneServers()); + break; + case INCLUDE: + // Don't remove either + break; + } + return serversToIgnore; + }; + } + private final Supplier> serversToIgnoreSupplier; @Override diff --git a/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java b/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java index 61602dc7cfe6..58e3162fe4dd 100644 --- a/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java +++ b/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java @@ -121,11 +121,6 @@ public boolean isEmpty() } } - public List getCandidates(final int numCandidates) - { - return getCandidates(numCandidates, HistoricalFilter.IDENTITIY_FILTER); - } - public List getCandidates(final int numCandidates, HistoricalFilter filter) { List candidates; @@ -150,11 +145,6 @@ public List getCandidates(final int numCandidates, Historic } } - public List getAllServers() - { - return getAllServers(HistoricalFilter.IDENTITIY_FILTER); - } - public List getAllServers(HistoricalFilter filter) { final List servers = new ArrayList<>(); @@ -177,12 +167,6 @@ public List getAllServers(HistoricalFilter filter) return servers; } - @Nullable - public QueryableDruidServer pick(@Nullable Query query) - { - return pick(query, HistoricalFilter.IDENTITIY_FILTER); - } - @Nullable public QueryableDruidServer pick(@Nullable Query query, HistoricalFilter filter) { diff --git a/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java b/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java index d1b034db89ba..51f35b325114 100644 --- a/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java +++ b/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java @@ -23,11 +23,14 @@ import com.fasterxml.jackson.jaxrs.smile.SmileMediaTypes; import com.google.inject.Inject; import com.sun.jersey.spi.container.ResourceFilters; +import org.apache.druid.client.CoordinatorDynamicConfigView; import org.apache.druid.client.ServerViewUtil; import org.apache.druid.client.TimelineServerView; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.guice.annotations.Json; import org.apache.druid.guice.annotations.Self; import org.apache.druid.guice.annotations.Smile; +import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.Query; import org.apache.druid.query.planning.ExecutionVertex; import org.apache.druid.server.http.security.StateResourceFilter; @@ -53,6 +56,7 @@ public class BrokerQueryResource extends QueryResource { private final TimelineServerView brokerServerView; + private final CoordinatorDynamicConfigView configView; @Inject public BrokerQueryResource( @@ -64,7 +68,8 @@ public BrokerQueryResource( AuthorizerMapper authorizerMapper, ResponseContextConfig responseContextConfig, @Self DruidNode selfNode, - TimelineServerView brokerServerView + TimelineServerView brokerServerView, + CoordinatorDynamicConfigView configView ) { super( @@ -78,6 +83,7 @@ public BrokerQueryResource( selfNode ); this.brokerServerView = brokerServerView; + this.configView = configView; } @POST @@ -89,6 +95,7 @@ public Response getQueryTargets( InputStream in, @QueryParam("pretty") String pretty, @QueryParam("numCandidates") @DefaultValue("-1") int numCandidates, + @QueryParam("cloneQueryMode") CloneQueryMode cloneQueryMode, @Context final HttpServletRequest req ) throws IOException { @@ -96,12 +103,14 @@ public Response getQueryTargets( try { Query query = ioReaderWriter.getRequestMapper().readValue(in, Query.class); ExecutionVertex ev = ExecutionVertex.of(query); + HistoricalFilter historicalFilter = new HistoricalFilter(configView, cloneQueryMode == null ? CloneQueryMode.EXCLUDE : cloneQueryMode); return ioReaderWriter.getResponseWriter().ok( ServerViewUtil.getTargetLocations( brokerServerView, ev.getBaseTableDataSource(), ev.getEffectiveQuerySegmentSpec().getIntervals(), - numCandidates + numCandidates, + historicalFilter ) ); } diff --git a/server/src/main/java/org/apache/druid/server/ClientInfoResource.java b/server/src/main/java/org/apache/druid/server/ClientInfoResource.java index 212b61990b7d..aff2939341d6 100644 --- a/server/src/main/java/org/apache/druid/server/ClientInfoResource.java +++ b/server/src/main/java/org/apache/druid/server/ClientInfoResource.java @@ -25,15 +25,18 @@ import com.google.common.collect.Maps; import com.google.inject.Inject; import com.sun.jersey.spi.container.ResourceFilters; +import org.apache.druid.client.CoordinatorDynamicConfigView; import org.apache.druid.client.DruidDataSource; import org.apache.druid.client.FilteredServerInventoryView; import org.apache.druid.client.ServerViewUtil; import org.apache.druid.client.TimelineServerView; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.java.util.common.DateTimes; import org.apache.druid.java.util.common.Intervals; import org.apache.druid.java.util.common.JodaUtils; import org.apache.druid.java.util.common.logger.Logger; +import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.LocatedSegmentDescriptor; import org.apache.druid.query.TableDataSource; import org.apache.druid.query.metadata.SegmentMetadataQueryConfig; @@ -86,6 +89,7 @@ public class ClientInfoResource private SegmentMetadataQueryConfig segmentMetadataQueryConfig; private final AuthConfig authConfig; private final AuthorizerMapper authorizerMapper; + private final CoordinatorDynamicConfigView configView; @Inject public ClientInfoResource( @@ -93,7 +97,8 @@ public ClientInfoResource( TimelineServerView timelineServerView, SegmentMetadataQueryConfig segmentMetadataQueryConfig, AuthConfig authConfig, - AuthorizerMapper authorizerMapper + AuthorizerMapper authorizerMapper, + CoordinatorDynamicConfigView configView ) { this.serverInventoryView = serverInventoryView; @@ -102,6 +107,7 @@ public ClientInfoResource( new SegmentMetadataQueryConfig() : segmentMetadataQueryConfig; this.authConfig = authConfig; this.authorizerMapper = authorizerMapper; + this.configView = configView; } @GET @@ -300,6 +306,7 @@ public Iterable getQueryTargets( @PathParam("dataSourceName") String datasource, @QueryParam("intervals") String intervals, @QueryParam("numCandidates") @DefaultValue("-1") int numCandidates, + @QueryParam("cloneQueryMode") CloneQueryMode cloneQueryMode, @Context final HttpServletRequest req ) { @@ -308,7 +315,8 @@ public Iterable getQueryTargets( intervalList.add(Intervals.of(interval.trim())); } List condensed = JodaUtils.condenseIntervals(intervalList); - return ServerViewUtil.getTargetLocations(timelineServerView, datasource, condensed, numCandidates); + HistoricalFilter historicalFilter = new HistoricalFilter(configView, cloneQueryMode == null ? CloneQueryMode.EXCLUDE : cloneQueryMode); + return ServerViewUtil.getTargetLocations(timelineServerView, datasource, condensed, numCandidates, historicalFilter); } protected DateTime getCurrentTime() diff --git a/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java b/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java index 0afde5424945..973feb478bc6 100644 --- a/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java +++ b/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java @@ -30,6 +30,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.apache.druid.client.selector.HighestPriorityTierSelectorStrategy; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.RandomServerSelectorStrategy; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.curator.CuratorTestBase; @@ -128,7 +129,7 @@ public void testSingleServerAddedRemovedSegment() throws Exception ServerSelector selector = (actualPartitionHolder.iterator().next()).getObject(); Assert.assertFalse(selector.isEmpty()); Assert.assertEquals(segment, selector.getSegment()); - Assert.assertEquals(druidServer, selector.pick(null).getServer()); + Assert.assertEquals(druidServer, selector.pick(null, HistoricalFilter.IDENTITY_FILTER).getServer()); Assert.assertNotNull(timeline.findChunk(intervals, "v1", partition)); unannounceSegmentForServer(druidServer, segment, zkPathsConfig); @@ -387,9 +388,9 @@ public void testMultipleTiers() throws Exception // Verify that the ServerSelector always picks Tier 1 for (int i = 0; i < 5; ++i) { - Assert.assertEquals(server21, selector.pick(null).getServer()); + Assert.assertEquals(server21, selector.pick(null, HistoricalFilter.IDENTITY_FILTER).getServer()); } - Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2)); + Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER)); } @Test @@ -447,9 +448,9 @@ public void testRealtimeTasksNotWatched() throws Exception // Verify that the ServerSelector always picks the Historical server for (int i = 0; i < 5; ++i) { - Assert.assertEquals(historicalServer, selector.pick(null).getServer()); + Assert.assertEquals(historicalServer, selector.pick(null, HistoricalFilter.IDENTITY_FILTER).getServer()); } - Assert.assertEquals(Collections.singletonList(historicalServer.getMetadata()), selector.getCandidates(2)); + Assert.assertEquals(Collections.singletonList(historicalServer.getMetadata()), selector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER)); } @Test @@ -509,9 +510,9 @@ public void testIgnoredTiers() throws Exception // Verify that the ServerSelector always picks Tier 1 for (int i = 0; i < 5; ++i) { - Assert.assertEquals(server21, selector.pick(null).getServer()); + Assert.assertEquals(server21, selector.pick(null, HistoricalFilter.IDENTITY_FILTER).getServer()); } - Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2)); + Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER)); } @Test(expected = ISE.class) @@ -591,7 +592,7 @@ private void assertValues( ServerSelector selector = ((SingleElementPartitionChunk) actualPartitionHolder.iterator() .next()).getObject(); Assert.assertFalse(selector.isEmpty()); - Assert.assertEquals(expectedPair.rhs.rhs.lhs, selector.pick(null).getServer()); + Assert.assertEquals(expectedPair.rhs.rhs.lhs, selector.pick(null, HistoricalFilter.IDENTITY_FILTER).getServer()); Assert.assertEquals(expectedPair.rhs.rhs.rhs, selector.getSegment()); } } diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java index 7139853752e5..d7f6025a106f 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.primitives.Bytes; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.query.CacheStrategy; import org.apache.druid.query.DataSource; @@ -86,7 +87,7 @@ public void testComputeEtag_nonHistorical() makeHistoricalServerSelector(0), makeRealtimeServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, QUERY_CACHE_KEY); + String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, QUERY_CACHE_KEY); Assert.assertNull(actual); } @@ -99,14 +100,14 @@ public void testComputeEtag_DifferentHistoricals() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, QUERY_CACHE_KEY); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, QUERY_CACHE_KEY); Assert.assertNotNull(actual1); selectors = ImmutableSet.of( makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, QUERY_CACHE_KEY); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, QUERY_CACHE_KEY); Assert.assertNotNull(actual2); Assert.assertEquals("cache key should not change for same server selectors", actual1, actual2); @@ -114,7 +115,7 @@ public void testComputeEtag_DifferentHistoricals() makeHistoricalServerSelector(2), makeHistoricalServerSelector(1) ); - String actual3 = keyManager.computeResultLevelCachingEtag(selectors, QUERY_CACHE_KEY); + String actual3 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, QUERY_CACHE_KEY); Assert.assertNotNull(actual3); Assert.assertNotEquals(actual1, actual3); } @@ -128,10 +129,10 @@ public void testComputeEtag_DifferentQueryCacheKey() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, new byte[]{1, 2}); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, new byte[]{1, 2}); Assert.assertNotNull(actual1); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, new byte[]{3, 4}); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, new byte[]{3, 4}); Assert.assertNotNull(actual2); Assert.assertNotEquals(actual1, actual2); } @@ -146,14 +147,14 @@ public void testComputeEtag_nonJoinDataSource() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, FULL_QUERY_CACHE_KEY); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, FULL_QUERY_CACHE_KEY); Assert.assertNotNull(actual1); selectors = ImmutableSet.of( makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, null); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, null); Assert.assertNotNull(actual2); Assert.assertEquals(actual1, actual2); } @@ -169,7 +170,7 @@ public void testComputeEtag_joinWithUnsupportedCaching() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, null); Assert.assertNull(actual); } @@ -187,7 +188,7 @@ public void testComputeEtag_noEffectifBySegment() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, null); Assert.assertNotNull(actual); } @@ -207,7 +208,7 @@ public void testComputeEtag_noEffectIfUseAndPopulateFalse() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, null); Assert.assertNotNull(actual); } @@ -306,7 +307,7 @@ private SegmentServerSelector makeServerSelector(boolean isHistorical, int parti 0 ); expect(server.isSegmentReplicationTarget()).andReturn(isHistorical).anyTimes(); - expect(serverSelector.pick(query)).andReturn(queryableDruidServer).anyTimes(); + expect(serverSelector.pick(query, HistoricalFilter.IDENTITY_FILTER)).andReturn(queryableDruidServer).anyTimes(); expect(queryableDruidServer.getServer()).andReturn(server).anyTimes(); expect(serverSelector.getSegment()).andReturn(segment).anyTimes(); replay(serverSelector, queryableDruidServer, server); diff --git a/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java b/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java index 1bdcec158268..e9598efaafb1 100644 --- a/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java +++ b/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java @@ -27,6 +27,7 @@ import com.google.common.util.concurrent.SettableFuture; import org.apache.druid.client.selector.ConnectionCountServerSelectorStrategy; import org.apache.druid.client.selector.HighestPriorityTierSelectorStrategy; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.jackson.DefaultObjectMapper; import org.apache.druid.java.util.common.DateTimes; @@ -243,7 +244,7 @@ public void testRun() throws Exception Assert.assertEquals(2, client2.getNumOpenConnections()); - Assert.assertEquals(serverSelector.pick(null), queryableDruidServer2); + Assert.assertEquals(serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER), queryableDruidServer2); EasyMock.verify(httpClient); } diff --git a/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java b/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java index d914e9e59433..0ad96a81cfd5 100644 --- a/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java +++ b/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java @@ -50,7 +50,7 @@ public void testDifferentConnectionCount() ServerSelector serverSelector = initSelector(s1, s2, s3); for (int i = 0; i < 100; ++i) { - Assert.assertEquals(s2, serverSelector.pick(null)); + Assert.assertEquals(s2, serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER)); } } @@ -63,7 +63,7 @@ public void testBalancerTieBreaking() Set pickedServers = new HashSet<>(); for (int i = 0; i < 100; ++i) { - pickedServers.add(serverSelector.pick(null).getServer().getName()); + pickedServers.add(serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER).getServer().getName()); } Assert.assertTrue( "Multiple servers should be selected when the number of connections is equal.", diff --git a/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java b/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java index e6afb1cba9cf..58e88a27eaa3 100644 --- a/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java +++ b/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java @@ -240,10 +240,10 @@ private void testTierSelectorStrategy( serverSelector.addServerAndUpdateSegment(server, serverSelector.getSegment()); } - Assert.assertEquals(expectedSelection[0], serverSelector.pick(null)); - Assert.assertEquals(expectedSelection[0], serverSelector.pick(EasyMock.createMock(Query.class))); - Assert.assertEquals(expectedCandidates, serverSelector.getCandidates(-1)); - Assert.assertEquals(expectedCandidates.subList(0, 2), serverSelector.getCandidates(2)); + Assert.assertEquals(expectedSelection[0], serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER)); + Assert.assertEquals(expectedSelection[0], serverSelector.pick(EasyMock.createMock(Query.class), HistoricalFilter.IDENTITY_FILTER)); + Assert.assertEquals(expectedCandidates, serverSelector.getCandidates(-1, HistoricalFilter.IDENTITY_FILTER)); + Assert.assertEquals(expectedCandidates.subList(0, 2), serverSelector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER)); } @Test diff --git a/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java b/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java index d7f2d98e8c44..c810e5c2d1c3 100644 --- a/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java @@ -407,6 +407,7 @@ private ClientInfoResource getResourceTestHelper( timelineServerView, segmentMetadataQueryConfig, new AuthConfig(), + null, null ) { From bc53f0c30b78c263d276a4476bc9e4cdbb3559c6 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Tue, 15 Apr 2025 21:44:00 +0530 Subject: [PATCH 19/38] Fix tests --- .../CachingClusteredClientBenchmark.java | 17 +------ .../client/CoordinatorDynamicConfigView.java | 2 +- .../client/selector/HistoricalFilter.java | 2 +- .../client/CachingClusteredClientTest.java | 17 +------ .../TestCoordinatorDynamicConfigView.java | 50 +++++++++++++++++++ ...yRunnerBasedOnClusteredClientTestBase.java | 4 +- 6 files changed, 58 insertions(+), 34 deletions(-) create mode 100644 server/src/test/java/org/apache/druid/client/TestCoordinatorDynamicConfigView.java diff --git a/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java b/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java index e85f299549cf..1a48310d9105 100644 --- a/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java +++ b/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java @@ -28,10 +28,10 @@ import com.google.common.collect.Maps; import com.google.common.collect.Ordering; import org.apache.druid.client.CachingClusteredClient; -import org.apache.druid.client.CoordinatorDynamicConfigView; import org.apache.druid.client.DruidServer; import org.apache.druid.client.ImmutableDruidServer; import org.apache.druid.client.QueryableDruidServer; +import org.apache.druid.client.TestCoordinatorDynamicConfigView; import org.apache.druid.client.TimelineServerView; import org.apache.druid.client.cache.CacheConfig; import org.apache.druid.client.cache.CachePopulatorStats; @@ -323,20 +323,7 @@ public boolean useParallelMergePool() forkJoinPool, QueryStackTests.DEFAULT_NOOP_SCHEDULER, new NoopServiceEmitter(), - new CoordinatorDynamicConfigView(null) - { - @Override - public Set getTargetCloneServers() - { - return Set.of(); - } - - @Override - public Set getSourceClusterServers() - { - return Set.of(); - } - } + new TestCoordinatorDynamicConfigView(Set.of(), Set.of()) ); } diff --git a/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java b/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java index 9572eec6b2cc..d10fe5334c1c 100644 --- a/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java +++ b/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java @@ -53,7 +53,7 @@ public Set getTargetCloneServers() return coordinatorDynamicConfig.getCloneServers().keySet(); } - public Set getSourceClusterServers() + public Set getSourceCloneServers() { CoordinatorDynamicConfig coordinatorDynamicConfig = config.get(); return new HashSet<>(coordinatorDynamicConfig.getCloneServers().values()); diff --git a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java index 70042512dc62..40a9a0c63929 100644 --- a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java +++ b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java @@ -48,7 +48,7 @@ public HistoricalFilter(CoordinatorDynamicConfigView configView, CloneQueryMode switch (cloneQueryMode) { case ONLY: // Remove clone sources, so that targets are queried. - serversToIgnore.addAll(configView.getSourceClusterServers()); + serversToIgnore.addAll(configView.getSourceCloneServers()); break; case EXCLUDE: // Remove clone sources, so that targets are queried. diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java index f8eed1881be8..c82c6e4ea480 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java @@ -26,7 +26,6 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Ordering; @@ -145,7 +144,6 @@ import org.junit.runners.Parameterized; import javax.annotation.Nullable; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -2712,20 +2710,7 @@ public int getDefaultMaxQueryParallelism() new ServerConfig() ), new NoopServiceEmitter(), - new CoordinatorDynamicConfigView(null) - { - @Override - public Set getTargetCloneServers() - { - return ImmutableSet.of(); - } - - @Override - public Set getSourceClusterServers() - { - return ImmutableSet.of(); - } - } + new TestCoordinatorDynamicConfigView(Set.of(), Set.of()) ); } diff --git a/server/src/test/java/org/apache/druid/client/TestCoordinatorDynamicConfigView.java b/server/src/test/java/org/apache/druid/client/TestCoordinatorDynamicConfigView.java new file mode 100644 index 000000000000..5b2adbf0c899 --- /dev/null +++ b/server/src/test/java/org/apache/druid/client/TestCoordinatorDynamicConfigView.java @@ -0,0 +1,50 @@ +/* + * 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.client; + +import java.util.Set; + +public class TestCoordinatorDynamicConfigView extends CoordinatorDynamicConfigView +{ + private final Set targetServers; + private final Set sourceServers; + + public TestCoordinatorDynamicConfigView( + Set targetServers, + Set sourceServers + ) + { + super(null); + this.targetServers = targetServers; + this.sourceServers = sourceServers; + } + + @Override + public Set getTargetCloneServers() + { + return targetServers; + } + + @Override + public Set getSourceCloneServers() + { + return sourceServers; + } +} diff --git a/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java b/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java index f2a7234ae474..31e64957a749 100644 --- a/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java +++ b/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java @@ -27,6 +27,7 @@ import org.apache.druid.client.DirectDruidClient; import org.apache.druid.client.DruidServer; import org.apache.druid.client.SimpleServerView; +import org.apache.druid.client.TestCoordinatorDynamicConfigView; import org.apache.druid.client.TestHttpClient; import org.apache.druid.client.TestHttpClient.SimpleServerManager; import org.apache.druid.client.cache.CacheConfig; @@ -61,6 +62,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.UUID; import java.util.concurrent.ForkJoinPool; import java.util.stream.Collectors; @@ -133,7 +135,7 @@ public void setupTestBase() ForkJoinPool.commonPool(), QueryStackTests.DEFAULT_NOOP_SCHEDULER, new NoopServiceEmitter(), - null + new TestCoordinatorDynamicConfigView(Set.of(), Set.of()) ); servers = new ArrayList<>(); } From b6ebf32e415504c571a8ab51d4481babe52a0655 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Fri, 18 Apr 2025 19:10:55 +0530 Subject: [PATCH 20/38] Address review comments --- docs/querying/query-context.md | 2 +- .../movingaverage/MovingAverageQueryTest.java | 4 +- .../apache/druid/query/CloneQueryMode.java | 2 +- .../client/CoordinatorDynamicConfigView.java | 53 ++++++++++++------- .../client/selector/HistoricalFilter.java | 26 ++++----- .../druid/server/BrokerQueryResource.java | 6 ++- .../DruidInternalDynamicConfigResource.java | 8 +-- .../coordinator/CloneStatusManager.java | 2 +- .../coordinator/CoordinatorDynamicConfig.java | 25 +++++++++ .../http/CoordinatorDynamicConfigSyncer.java | 2 +- .../server/http/CoordinatorResource.java | 2 +- ...chingClusteredClientFunctionalityTest.java | 2 +- .../CachingClusteredClientPerfTest.java | 3 +- 13 files changed, 91 insertions(+), 46 deletions(-) diff --git a/docs/querying/query-context.md b/docs/querying/query-context.md index e867e6d8f162..61ddf0f96178 100644 --- a/docs/querying/query-context.md +++ b/docs/querying/query-context.md @@ -66,7 +66,7 @@ See [SQL query context](sql-query-context.md) for other query context parameters |`debug`| `false` | Flag indicating whether to enable debugging outputs for the query. When set to false, no additional logs will be produced (logs produced will be entirely dependent on your logging level). When set to true, the following addition logs will be produced:
- Log the stack trace of the exception (if any) produced by the query | |`setProcessingThreadNames`|`true`| Whether processing thread names will be set to `queryType_dataSource_intervals` while processing a query. This aids in interpreting thread dumps, and is on by default. Query overhead can be reduced slightly by setting this to `false`. This has a tiny effect in most scenarios, but can be meaningful in high-QPS, low-per-segment-processing-time scenarios. | |`sqlPlannerBloat`|`1000`|Calcite parameter which controls whether to merge two Project operators when inlining expressions causes complexity to increase. Implemented as a workaround to exception `There are not enough rules to produce a node with desired properties: convention=DRUID, sort=[]` thrown after rejecting the merge of two projects.| -|`cloneQueryMode`|`EXCLUDE`| Indicates whether clone Historicals should be queried by brokers. Clone servers are created by the `cloneServers` Coordinator dynamic configuration. Possible values are `EXCLUDE`, `INCLUDE` and `ONLY`. `EXCLUDE` means that clone Historicals are not queried by the broker. `ONLY` indicates that when given a choice between the clone Historical and the original Historical which is being cloned, the broker chooses the clones; Historicals which are not involved in the cloning process will still be queried. `INCLUDE` means that broker queries any Historical without regarding clone status. | +|`cloneQueryMode`|`EXCLUDE`| Indicates whether clone Historicals should be queried by brokers. Clone servers are created by the `cloneServers` Coordinator dynamic configuration. Possible values are `EXCLUDE`, `INCLUDE` and `CLONE_PREFERRED`. `EXCLUDE` means that clone Historicals are not queried by the broker. `CLONE_PREFERRED` indicates that when given a choice between the clone Historical and the original Historical which is being cloned, the broker chooses the clones; Historicals which are not involved in the cloning process will still be queried. `INCLUDE` means that broker queries any Historical without regarding clone status. This parameter only affects native queries; MSQ does not query Historicals directly, and Dart will not respect this context parameter.| ## Parameters by query type diff --git a/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java b/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java index c00d996291da..b9450f956deb 100644 --- a/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java +++ b/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java @@ -34,6 +34,7 @@ import org.apache.druid.client.CachingClusteredClient; import org.apache.druid.client.DruidServer; import org.apache.druid.client.ImmutableDruidServer; +import org.apache.druid.client.TestCoordinatorDynamicConfigView; import org.apache.druid.client.TimelineServerView; import org.apache.druid.client.cache.CacheConfig; import org.apache.druid.client.cache.CachePopulatorStats; @@ -94,6 +95,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.ForkJoinPool; @@ -366,7 +368,7 @@ public void registerServerRemovedCallback(Executor exec, ServerRemovedCallback c ForkJoinPool.commonPool(), QueryStackTests.DEFAULT_NOOP_SCHEDULER, new NoopServiceEmitter(), - null + new TestCoordinatorDynamicConfigView(Set.of(), Set.of()) ); ClientQuerySegmentWalker walker = new ClientQuerySegmentWalker( diff --git a/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java b/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java index 026677e7344f..979d3cb30aef 100644 --- a/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java +++ b/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java @@ -21,7 +21,7 @@ public enum CloneQueryMode { - ONLY, + CLONE_PREFERRED, INCLUDE, EXCLUDE } diff --git a/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java b/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java index d10fe5334c1c..da8580a8d977 100644 --- a/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java +++ b/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java @@ -19,59 +19,74 @@ package org.apache.druid.client; +import com.google.common.collect.ImmutableSet; +import com.google.errorprone.annotations.concurrent.GuardedBy; import com.google.inject.Inject; import org.apache.druid.client.coordinator.CoordinatorClient; import org.apache.druid.java.util.common.lifecycle.LifecycleStart; import org.apache.druid.java.util.common.logger.Logger; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; -import java.util.HashSet; +import javax.validation.constraints.NotNull; +import java.util.Map; import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; public class CoordinatorDynamicConfigView { private static final Logger log = new Logger(CoordinatorDynamicConfigView.class); private final CoordinatorClient coordinatorClient; + @GuardedBy("this") + private CoordinatorDynamicConfig config; + @GuardedBy("this") + private Set sourceCloneServers; + @GuardedBy("this") + private Set targetCloneServers; + @Inject public CoordinatorDynamicConfigView(CoordinatorClient coordinatorClient) { this.coordinatorClient = coordinatorClient; } - private final AtomicReference config = new AtomicReference<>(); - - public CoordinatorDynamicConfig getConfig() + public synchronized CoordinatorDynamicConfig getDynamicConfiguration() { - return config.get(); + return config; } - public Set getTargetCloneServers() + public synchronized void setDynamicConfiguration(@NotNull CoordinatorDynamicConfig updatedConfig) { - CoordinatorDynamicConfig coordinatorDynamicConfig = config.get(); - return coordinatorDynamicConfig.getCloneServers().keySet(); + config = updatedConfig.snapshot(); + Map cloneServers = config.getCloneServers(); + sourceCloneServers = ImmutableSet.copyOf(cloneServers.keySet()); + targetCloneServers = ImmutableSet.copyOf(cloneServers.values()); } - public Set getSourceCloneServers() + public synchronized Set getSourceCloneServers() { - CoordinatorDynamicConfig coordinatorDynamicConfig = config.get(); - return new HashSet<>(coordinatorDynamicConfig.getCloneServers().values()); + return sourceCloneServers; } - public void updateCloneServers(CoordinatorDynamicConfig updatedConfig) + public synchronized Set getTargetCloneServers() { - config.set(updatedConfig); + return targetCloneServers; } @LifecycleStart - public void start() throws Exception + public void start() { - log.info("Fetching coordinator dynamic configuration."); + try { + log.info("Fetching coordinator dynamic configuration."); - CoordinatorDynamicConfig coordinatorDynamicConfig = coordinatorClient.getCoordinatorDynamicConfig().get(); - updateCloneServers(coordinatorDynamicConfig); + CoordinatorDynamicConfig coordinatorDynamicConfig = coordinatorClient.getCoordinatorDynamicConfig().get(); + setDynamicConfiguration(coordinatorDynamicConfig); - log.info("Successfully initialized dynamic config: [%s]", coordinatorDynamicConfig); + log.info("Successfully initialized dynamic config: [%s]", coordinatorDynamicConfig); + } + catch (Exception e) { + // If the fetch fails, the broker should not serve queries. Throw the exception and try again on restart. + log.error(e, "Failed to initialize coordinator dynamic config"); + throw new RuntimeException(e); + } } } diff --git a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java index 40a9a0c63929..a40b78a1e650 100644 --- a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java +++ b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java @@ -25,7 +25,6 @@ import org.apache.druid.client.QueryableDruidServer; import org.apache.druid.query.CloneQueryMode; -import java.util.HashSet; import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; @@ -34,6 +33,7 @@ public class HistoricalFilter implements Function>, Int2ObjectRBTreeMap>> { public static final HistoricalFilter IDENTITY_FILTER = new HistoricalFilter(ImmutableSet::of); + private final Supplier> serversToIgnoreSupplier; public HistoricalFilter(Supplier> serversToIgnoreSupplier) { @@ -43,31 +43,31 @@ public HistoricalFilter(Supplier> serversToIgnoreSupplier) public HistoricalFilter(CoordinatorDynamicConfigView configView, CloneQueryMode cloneQueryMode) { this.serversToIgnoreSupplier = () -> { - final Set serversToIgnore = new HashSet<>(); - switch (cloneQueryMode) { - case ONLY: + case CLONE_PREFERRED: // Remove clone sources, so that targets are queried. - serversToIgnore.addAll(configView.getSourceCloneServers()); - break; + return configView.getSourceCloneServers(); case EXCLUDE: // Remove clone sources, so that targets are queried. - serversToIgnore.addAll(configView.getTargetCloneServers()); - break; + return configView.getTargetCloneServers(); case INCLUDE: // Don't remove either - break; + return ImmutableSet.of(); + default: + throw new IllegalStateException("Unexpected value: " + cloneQueryMode); } - return serversToIgnore; }; } - private final Supplier> serversToIgnoreSupplier; - @Override public Int2ObjectRBTreeMap> apply(Int2ObjectRBTreeMap> historicalServers) { - final Set serversToIgnore = serversToIgnoreSupplier.get(); + Set serversToIgnore = serversToIgnoreSupplier.get(); + + if (serversToIgnore.isEmpty()) { + return historicalServers; + } + final Int2ObjectRBTreeMap> filteredHistoricals = new Int2ObjectRBTreeMap<>(); for (int priority : historicalServers.keySet()) { Set servers = historicalServers.get(priority); diff --git a/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java b/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java index 51f35b325114..f58243bedc16 100644 --- a/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java +++ b/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java @@ -32,11 +32,13 @@ import org.apache.druid.guice.annotations.Smile; import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.Query; +import org.apache.druid.query.QueryContexts; import org.apache.druid.query.planning.ExecutionVertex; import org.apache.druid.server.http.security.StateResourceFilter; import org.apache.druid.server.security.AuthConfig; import org.apache.druid.server.security.AuthorizerMapper; +import javax.annotation.Nullable; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.DefaultValue; @@ -95,7 +97,7 @@ public Response getQueryTargets( InputStream in, @QueryParam("pretty") String pretty, @QueryParam("numCandidates") @DefaultValue("-1") int numCandidates, - @QueryParam("cloneQueryMode") CloneQueryMode cloneQueryMode, + @QueryParam("cloneQueryMode") @Nullable CloneQueryMode cloneQueryMode, @Context final HttpServletRequest req ) throws IOException { @@ -103,7 +105,7 @@ public Response getQueryTargets( try { Query query = ioReaderWriter.getRequestMapper().readValue(in, Query.class); ExecutionVertex ev = ExecutionVertex.of(query); - HistoricalFilter historicalFilter = new HistoricalFilter(configView, cloneQueryMode == null ? CloneQueryMode.EXCLUDE : cloneQueryMode); + HistoricalFilter historicalFilter = new HistoricalFilter(configView, cloneQueryMode == null ? QueryContexts.DEFAULT_CLONE_QUERY_MODE : cloneQueryMode); return ioReaderWriter.getResponseWriter().ok( ServerViewUtil.getTargetLocations( brokerServerView, diff --git a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java index e3aab85bafed..c979963f7393 100644 --- a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java +++ b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java @@ -48,18 +48,18 @@ public DruidInternalDynamicConfigResource(CoordinatorDynamicConfigView coordinat @Produces(MediaType.APPLICATION_JSON) @ResourceFilters(ConfigResourceFilter.class) @Path("/coordinatorDynamicConfig") - public Response getDatasource() + public Response getDynamicConfig() { - return Response.ok(coordinatorDynamicConfigView.getConfig()).build(); + return Response.ok(coordinatorDynamicConfigView.getDynamicConfiguration()).build(); } @POST @Consumes(MediaType.APPLICATION_JSON) @ResourceFilters(ConfigResourceFilter.class) @Path("/coordinatorDynamicConfig") - public Response setDatasource(final CoordinatorDynamicConfig dynamicConfig) + public Response setDynamicConfig(final CoordinatorDynamicConfig dynamicConfig) { - coordinatorDynamicConfigView.updateCloneServers(dynamicConfig); + coordinatorDynamicConfigView.setDynamicConfiguration(dynamicConfig); return Response.ok("OK").build(); } } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java index b0015ba09afb..9945c58320f7 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java @@ -84,7 +84,7 @@ public void updateStats(Map historicalMap, Map validateDebugDimensions(Map debug return validDebugDimensions; } + public CoordinatorDynamicConfig snapshot() + { + return new CoordinatorDynamicConfig( + markSegmentAsUnusedDelayMillis, + maxSegmentsToMove, + replicantLifetime, + replicationThrottleLimit, + balancerComputeThreads, + ImmutableSet.copyOf(specificDataSourcesToKillUnusedSegmentsIn), + killTaskSlotRatio, + maxKillTaskSlots, + ImmutableSet.copyOf(dataSourcesToNotKillStalePendingSegmentsIn), + maxSegmentsInNodeLoadingQueue, + ImmutableSet.copyOf(decommissioningNodes), + pauseCoordination, + replicateAfterLoadTimeout, + useRoundRobinSegmentAssignment, + smartSegmentLoading, + ImmutableMap.copyOf(debugDimensions), + ImmutableSet.copyOf(turboLoadingNodes), + ImmutableMap.copyOf(cloneServers) + ); + } + private static Set parseJsonStringOrArray(Object jsonStringOrArray) { if (jsonStringOrArray instanceof String) { diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java index e0debe08b0a7..92bbd655cefc 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java @@ -144,8 +144,8 @@ private synchronized void invalidateInSyncBrokersIfNeeded() final CoordinatorDynamicConfig currentDynamicConfig = configManager.getCurrentDynamicConfig(); if (!currentDynamicConfig.equals(lastKnownConfig.get())) { // Config has changed, clear the inSync list. - lastKnownConfig.set(currentDynamicConfig); inSyncBrokers.clear(); + lastKnownConfig.set(currentDynamicConfig); } } diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java index d4338c5f44f4..64be2e6ed996 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java @@ -178,7 +178,7 @@ public Response getBrokerStatus() @Path("/cloneStatus") @ResourceFilters(StateResourceFilter.class) @Produces(MediaType.APPLICATION_JSON) - public Response getCloneStatus(@QueryParam("targetServer") String targetServer) + public Response getCloneStatus(@QueryParam("targetServer") @Nullable String targetServer) { if (targetServer != null) { CloneStatusMetrics statusForServer = cloneStatusManager.getStatusForServer(targetServer); diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java index cd2a5b895383..8b7837924aa8 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java @@ -330,7 +330,7 @@ public int getDefaultMaxQueryParallelism() ForkJoinPool.commonPool(), QueryStackTests.DEFAULT_NOOP_SCHEDULER, new NoopServiceEmitter(), - null + new TestCoordinatorDynamicConfigView(Set.of(), Set.of()) ); } diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java index ff86d7480b7b..9699d88ca842 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java @@ -67,6 +67,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.concurrent.ForkJoinPool; import static org.mockito.ArgumentMatchers.any; @@ -140,7 +141,7 @@ public void testGetQueryRunnerForSegments_singleIntervalLargeSegments() ForkJoinPool.commonPool(), queryScheduler, new NoopServiceEmitter(), - null + new TestCoordinatorDynamicConfigView(Set.of(), Set.of()) ); Query fakeQuery = makeFakeQuery(interval); From 270ceeca9bde542faf9b0f395eed8669be821f40 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Sat, 19 Apr 2025 17:47:14 +0530 Subject: [PATCH 21/38] Add javadocs --- .../java/org/apache/druid/query/CloneQueryMode.java | 3 +++ .../druid/client/CoordinatorDynamicConfigView.java | 10 ++++++++++ .../druid/server/coordinator/CloneStatusMetrics.java | 3 +++ 3 files changed, 16 insertions(+) diff --git a/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java b/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java index 979d3cb30aef..bbcf831608b3 100644 --- a/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java +++ b/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java @@ -19,6 +19,9 @@ package org.apache.druid.query; +/** + * Enum used in the query context to determine if clone queries should be used by native queries. + */ public enum CloneQueryMode { CLONE_PREFERRED, diff --git a/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java b/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java index da8580a8d977..af1e14b86038 100644 --- a/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java +++ b/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java @@ -25,12 +25,18 @@ import org.apache.druid.client.coordinator.CoordinatorClient; import org.apache.druid.java.util.common.lifecycle.LifecycleStart; import org.apache.druid.java.util.common.logger.Logger; +import org.apache.druid.server.DruidInternalDynamicConfigResource; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import javax.validation.constraints.NotNull; import java.util.Map; import java.util.Set; +/** + * Broker view of the coordinator dynamic configuration, and its derived values such as target and source clone servers. + * This class is registered as a managed lifecycle to fetch the coordinator dynamic configuration on startup. Further + * updates are handled through {@link DruidInternalDynamicConfigResource}. + */ public class CoordinatorDynamicConfigView { private static final Logger log = new Logger(CoordinatorDynamicConfigView.class); @@ -54,6 +60,10 @@ public synchronized CoordinatorDynamicConfig getDynamicConfiguration() return config; } + /** + * Update the config view with a new coordinator dynamic config snapshot. Also updates the source and target clone + * servers based on the new dynamic configuration. + */ public synchronized void setDynamicConfiguration(@NotNull CoordinatorDynamicConfig updatedConfig) { config = updatedConfig.snapshot(); diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java index dfddeb3ee0c1..803b4bdcdd47 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java @@ -118,6 +118,9 @@ public String toString() '}'; } + /** + * Enum determining the status of the cloning process. + */ public enum Status { SOURCE_SERVER_MISSING, From 0ae068697863dedf8a10f4ede31e08cd494abbea Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Mon, 21 Apr 2025 10:07:08 +0530 Subject: [PATCH 22/38] Add test --- .../client/CoordinatorDynamicConfigView.java | 18 ++--- .../client/selector/HistoricalFilter.java | 18 ++--- .../coordinator/CoordinatorDynamicConfig.java | 12 ++-- .../CoordinatorDynamicConfigViewTest.java | 72 +++++++++++++++++++ .../TestCoordinatorDynamicConfigView.java | 4 +- .../http/CoordinatorDynamicConfigTest.java | 17 +++++ 6 files changed, 115 insertions(+), 26 deletions(-) create mode 100644 server/src/test/java/org/apache/druid/client/CoordinatorDynamicConfigViewTest.java diff --git a/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java b/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java index af1e14b86038..ceeb3214e9f1 100644 --- a/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java +++ b/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java @@ -45,9 +45,9 @@ public class CoordinatorDynamicConfigView @GuardedBy("this") private CoordinatorDynamicConfig config; @GuardedBy("this") - private Set sourceCloneServers; + private Set cloneServers; @GuardedBy("this") - private Set targetCloneServers; + private Set serversBeingCloned; @Inject public CoordinatorDynamicConfigView(CoordinatorClient coordinatorClient) @@ -67,19 +67,19 @@ public synchronized CoordinatorDynamicConfig getDynamicConfiguration() public synchronized void setDynamicConfiguration(@NotNull CoordinatorDynamicConfig updatedConfig) { config = updatedConfig.snapshot(); - Map cloneServers = config.getCloneServers(); - sourceCloneServers = ImmutableSet.copyOf(cloneServers.keySet()); - targetCloneServers = ImmutableSet.copyOf(cloneServers.values()); + final Map cloneServers = config.getCloneServers(); + this.cloneServers = ImmutableSet.copyOf(cloneServers.keySet()); + this.serversBeingCloned = ImmutableSet.copyOf(cloneServers.values()); } - public synchronized Set getSourceCloneServers() + public synchronized Set getClones() { - return sourceCloneServers; + return cloneServers; } - public synchronized Set getTargetCloneServers() + public synchronized Set getServersBeingCloned() { - return targetCloneServers; + return serversBeingCloned; } @LifecycleStart diff --git a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java index a40b78a1e650..71514c3f3c88 100644 --- a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java +++ b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java @@ -33,23 +33,23 @@ public class HistoricalFilter implements Function>, Int2ObjectRBTreeMap>> { public static final HistoricalFilter IDENTITY_FILTER = new HistoricalFilter(ImmutableSet::of); - private final Supplier> serversToIgnoreSupplier; + private final Supplier> serversToFilter; - public HistoricalFilter(Supplier> serversToIgnoreSupplier) + public HistoricalFilter(Supplier> serversToFilter) { - this.serversToIgnoreSupplier = serversToIgnoreSupplier; + this.serversToFilter = serversToFilter; } public HistoricalFilter(CoordinatorDynamicConfigView configView, CloneQueryMode cloneQueryMode) { - this.serversToIgnoreSupplier = () -> { + this.serversToFilter = () -> { switch (cloneQueryMode) { case CLONE_PREFERRED: - // Remove clone sources, so that targets are queried. - return configView.getSourceCloneServers(); + // Remove servers being cloned targets, so that clones are queried. + return configView.getServersBeingCloned(); case EXCLUDE: - // Remove clone sources, so that targets are queried. - return configView.getTargetCloneServers(); + // Remove clones, so that targets are queried. + return configView.getClones(); case INCLUDE: // Don't remove either return ImmutableSet.of(); @@ -62,7 +62,7 @@ public HistoricalFilter(CoordinatorDynamicConfigView configView, CloneQueryMode @Override public Int2ObjectRBTreeMap> apply(Int2ObjectRBTreeMap> historicalServers) { - Set serversToIgnore = serversToIgnoreSupplier.get(); + Set serversToIgnore = serversToFilter.get(); if (serversToIgnore.isEmpty()) { return historicalServers; diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java b/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java index d55eda5f8f2f..fe2deac695b3 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CoordinatorDynamicConfig.java @@ -200,19 +200,19 @@ public CoordinatorDynamicConfig snapshot() replicantLifetime, replicationThrottleLimit, balancerComputeThreads, - ImmutableSet.copyOf(specificDataSourcesToKillUnusedSegmentsIn), + specificDataSourcesToKillUnusedSegmentsIn != null ? ImmutableSet.copyOf(specificDataSourcesToKillUnusedSegmentsIn) : null, killTaskSlotRatio, maxKillTaskSlots, - ImmutableSet.copyOf(dataSourcesToNotKillStalePendingSegmentsIn), + dataSourcesToNotKillStalePendingSegmentsIn != null ? ImmutableSet.copyOf(dataSourcesToNotKillStalePendingSegmentsIn) : null, maxSegmentsInNodeLoadingQueue, - ImmutableSet.copyOf(decommissioningNodes), + decommissioningNodes != null ? ImmutableSet.copyOf(decommissioningNodes) : null, pauseCoordination, replicateAfterLoadTimeout, useRoundRobinSegmentAssignment, smartSegmentLoading, - ImmutableMap.copyOf(debugDimensions), - ImmutableSet.copyOf(turboLoadingNodes), - ImmutableMap.copyOf(cloneServers) + debugDimensions != null ? ImmutableMap.copyOf(debugDimensions) : null, + turboLoadingNodes != null ? ImmutableSet.copyOf(turboLoadingNodes) : null, + cloneServers != null ? ImmutableMap.copyOf(cloneServers) : null ); } diff --git a/server/src/test/java/org/apache/druid/client/CoordinatorDynamicConfigViewTest.java b/server/src/test/java/org/apache/druid/client/CoordinatorDynamicConfigViewTest.java new file mode 100644 index 000000000000..244698dffaf9 --- /dev/null +++ b/server/src/test/java/org/apache/druid/client/CoordinatorDynamicConfigViewTest.java @@ -0,0 +1,72 @@ +/* + * 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.client; + +import com.google.common.util.concurrent.Futures; +import org.apache.druid.client.coordinator.CoordinatorClient; +import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.Map; +import java.util.Set; + +public class CoordinatorDynamicConfigViewTest +{ + private CoordinatorDynamicConfigView target; + + private CoordinatorClient coordinatorClient; + private CoordinatorDynamicConfig config; + + + @Before + public void setUp() throws Exception + { + config = CoordinatorDynamicConfig.builder() + .withCloneServers(Map.of("host1", "host2")) + .build(); + coordinatorClient = Mockito.mock(CoordinatorClient.class); + Mockito.when(coordinatorClient.getCoordinatorDynamicConfig()).thenReturn(Futures.immediateFuture(config)); + target = new CoordinatorDynamicConfigView(coordinatorClient); + } + + @Test + public void testFetchesConfigOnStartup() + { + target.start(); + Mockito.verify(coordinatorClient, Mockito.times(1)).getCoordinatorDynamicConfig(); + Assert.assertEquals(config, target.getDynamicConfiguration()); + } + + @Test + public void testCreatesServerLists() + { + config = CoordinatorDynamicConfig.builder() + .withCloneServers(Map.of("host1", "host2", "host4", "host5")) + .build(); + + target.setDynamicConfiguration(config); + + Assert.assertEquals(Set.of("host1", "host4"), target.getClones()); + Assert.assertEquals(Set.of("host2", "host5"), target.getServersBeingCloned()); + } +} diff --git a/server/src/test/java/org/apache/druid/client/TestCoordinatorDynamicConfigView.java b/server/src/test/java/org/apache/druid/client/TestCoordinatorDynamicConfigView.java index 5b2adbf0c899..909e88b4a489 100644 --- a/server/src/test/java/org/apache/druid/client/TestCoordinatorDynamicConfigView.java +++ b/server/src/test/java/org/apache/druid/client/TestCoordinatorDynamicConfigView.java @@ -37,13 +37,13 @@ public TestCoordinatorDynamicConfigView( } @Override - public Set getTargetCloneServers() + public synchronized Set getServersBeingCloned() { return targetServers; } @Override - public Set getSourceCloneServers() + public synchronized Set getClones() { return sourceServers; } diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java index 22f3ccbdd4db..337e089b9707 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java @@ -591,6 +591,23 @@ public void testTurboLoadingNodes() Assert.assertEquals(SegmentLoadingMode.TURBO, config.getLoadingModeForServer("localhost:8083")); } + @Test + public void testSnapshot() + { + CoordinatorDynamicConfig config = CoordinatorDynamicConfig.builder() + .withMarkSegmentAsUnusedDelayMillis(1) + .withMaxSegmentsToMove(1) + .withReplicantLifetime(2) + .withReplicationThrottleLimit(4) + .withSmartSegmentLoading(true) + .withDecommissioningNodes(Set.of("host1", "host2")) + .withCloneServers(Map.of("host1", "host2")) + .build(); + + CoordinatorDynamicConfig snapshot = config.snapshot(); + Assert.assertEquals(config, snapshot); + } + @Test public void testEqualsAndHashCode() { From 25224c45c1cc559e078b727a8045c07e02ca1815 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Mon, 21 Apr 2025 12:21:59 +0530 Subject: [PATCH 23/38] Refactor --- .../CachingClusteredClientBenchmark.java | 8 +- docs/api-reference/service-status-api.md | 245 +++++++++--------- .../movingaverage/MovingAverageQueryTest.java | 8 +- ...ava => BrokerViewOfCoordinatorConfig.java} | 12 +- .../druid/client/CachingClusteredClient.java | 18 +- .../client/selector/HistoricalFilter.java | 4 +- .../druid/discovery/DiscoveryDruidNode.java | 16 -- .../druid/server/BrokerQueryResource.java | 16 +- .../druid/server/ClientInfoResource.java | 18 +- .../DruidInternalDynamicConfigResource.java | 18 +- .../coordinator/CloneStatusManager.java | 26 +- .../coordinator/CoordinatorDynamicConfig.java | 25 -- .../server/coordinator/DruidCoordinator.java | 4 +- ...tusMetrics.java => ServerCloneStatus.java} | 52 ++-- .../coordinator/duty/CloneHistoricals.java | 2 +- ...c.java => SendDynamicConfigToBrokers.java} | 4 +- .../http/CoordinatorDynamicConfigSyncer.java | 34 ++- .../CoordinatorDynamicConfigsResource.java | 32 ++- .../server/http/CoordinatorResource.java | 32 +-- ...=> BrokerViewOfCoordinatorConfigTest.java} | 8 +- ...ingClusteredClientCacheKeyManagerTest.java | 9 +- ...chingClusteredClientFunctionalityTest.java | 5 +- .../CachingClusteredClientPerfTest.java | 6 +- .../client/CachingClusteredClientTest.java | 5 +- .../TestCoordinatorDynamicConfigView.java | 50 ---- ...yRunnerBasedOnClusteredClientTestBase.java | 8 +- .../druid/server/ClientInfoResourceTest.java | 2 +- .../coordination/TestCoordinatorClient.java | 22 +- ...csTest.java => ServerCloneStatusTest.java} | 10 +- .../http/CoordinatorDynamicConfigTest.java | 17 -- ...CoordinatorDynamicConfigsResourceTest.java | 98 +++++++ .../server/http/CoordinatorResourceTest.java | 55 +--- .../java/org/apache/druid/cli/CliBroker.java | 4 +- 33 files changed, 432 insertions(+), 441 deletions(-) rename server/src/main/java/org/apache/druid/client/{CoordinatorDynamicConfigView.java => BrokerViewOfCoordinatorConfig.java} (89%) rename server/src/main/java/org/apache/druid/server/coordinator/{CloneStatusMetrics.java => ServerCloneStatus.java} (67%) rename server/src/main/java/org/apache/druid/server/coordinator/duty/{BrokerDynamicConfigSync.java => SendDynamicConfigToBrokers.java} (89%) rename server/src/test/java/org/apache/druid/client/{CoordinatorDynamicConfigViewTest.java => BrokerViewOfCoordinatorConfigTest.java} (91%) delete mode 100644 server/src/test/java/org/apache/druid/client/TestCoordinatorDynamicConfigView.java rename server/src/test/java/org/apache/druid/server/coordinator/{CloneStatusMetricsTest.java => ServerCloneStatusTest.java} (77%) create mode 100644 server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java diff --git a/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java b/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java index 1a48310d9105..6085771a4b07 100644 --- a/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java +++ b/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java @@ -28,10 +28,10 @@ import com.google.common.collect.Maps; import com.google.common.collect.Ordering; import org.apache.druid.client.CachingClusteredClient; +import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.DruidServer; import org.apache.druid.client.ImmutableDruidServer; import org.apache.druid.client.QueryableDruidServer; -import org.apache.druid.client.TestCoordinatorDynamicConfigView; import org.apache.druid.client.TimelineServerView; import org.apache.druid.client.cache.CacheConfig; import org.apache.druid.client.cache.CachePopulatorStats; @@ -106,6 +106,7 @@ import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.ResourceIdPopulatingQueryRunner; import org.apache.druid.server.coordination.ServerType; +import org.apache.druid.server.coordination.TestCoordinatorClient; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.DataSegment.PruneSpecsHolder; @@ -136,7 +137,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Optional; -import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.ForkJoinPool; @@ -308,6 +308,7 @@ public int getNumThreads() cachingClusteredClient = new CachingClusteredClient( conglomerate, serverView, + new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()), MapCache.create(0), JSON_MAPPER, new ForegroundCachePopulator(JSON_MAPPER, new CachePopulatorStats(), 0), @@ -322,8 +323,7 @@ public boolean useParallelMergePool() }, forkJoinPool, QueryStackTests.DEFAULT_NOOP_SCHEDULER, - new NoopServiceEmitter(), - new TestCoordinatorDynamicConfigView(Set.of(), Set.of()) + new NoopServiceEmitter() ); } diff --git a/docs/api-reference/service-status-api.md b/docs/api-reference/service-status-api.md index da440582363e..47b5e52f1fa4 100644 --- a/docs/api-reference/service-status-api.md +++ b/docs/api-reference/service-status-api.md @@ -658,6 +658,129 @@ Host: http://COORDINATOR_IP:COORDINATOR_PORT + +### Get Historical Cloning Status + +Retrieves the current status of Historical cloning from the Coordinator. + +#### URL + +`GET` `/druid/coordinator/v1/config/cloneStatus` + +#### Responses + + + + + + +
+ +*Successfully retrieved cloning status* + +
+
+ +#### Sample request + + + + + + +```shell +curl "http://COORDINATOR_IP:COORDINATOR_PORT/druid/coordinator/v1/config/cloneStatus" +``` + + + + + +```http +GET /druid/coordinator/v1/config/cloneStatus HTTP/1.1 +Host: http://COORDINATOR_IP:COORDINATOR_PORT +``` + + + + +#### Sample response + +
+ View the response + +```json +{ + "localhost:8083": { + "sourceServer": "localhost:8089", + "status": "LOADING", + "segmentLoadsRemaining": 0, + "segmenetsDropsRemaining": 0, + "bytesRemaining": 0 + } +} +``` + +
+ +### Get Broker dynamic configuration view + +Retrieves the list of Brokers which have an up-to-date view of Coordinator dynamic configuration. + +#### URL + +`GET` `/druid/coordinator/v1/config/syncedBrokers` + +#### Responses + + + + + + +
+ +*Successfully retrieved Broker Configuration view* + +
+
+ +#### Sample request + + + + + + +```shell +curl "http://COORDINATOR_IP:COORDINATOR_PORT/druid/coordinator/v1/config/syncedBrokers" +``` + + + + + +```http +GET /druid/coordinator/v1/config/syncedBrokers HTTP/1.1 +Host: http://COORDINATOR_IP:COORDINATOR_PORT +``` + + + + +#### Sample response + +
+ View the response + +```json +[ + "localhost:8082" +] +``` + +
+ ## Overlord ### Get Overlord leader address @@ -1335,125 +1458,3 @@ Host: http://BROKER_IP:BROKER_PORT #### Sample response A successful response to this endpoint results in an empty response body. - -### Get Historical Cloning Status - -Retrieves the current status of Historical cloning. - -#### URL - -`GET` `/druid/coordinator/v1/cloneStatus` - -#### Responses - - - - - - -
- -*Successfully retrieved cloning status* - -
-
- -#### Sample request - - - - - - -```shell -curl "http://COORDINATOR_IP:COORDINATOR_PORT/druid/coordinator/v1/cloneStatus" -``` - - - - - -```http -GET /druid/coordinator/v1/cloneStatus HTTP/1.1 -Host: http://COORDINATOR_IP:COORDINATOR_PORT -``` - - - - -#### Sample response - -
- View the response - -```json -{ - "localhost:8083": { - "sourceServer": "localhost:8089", - "status": "LOADING", - "segmentLoadsRemaining": 0, - "segmenetsDropsRemaining": 0, - "bytesRemaining": 0 - } -} -``` - -
- -### Get Broker dynamic configuration view - -Retrieves the list of Brokers which have an up-to-date view of Coordinator dynamic configuration. - -#### URL - -`GET` `/druid/coordinator/v1/brokerConfigurationStatus` - -#### Responses - - - - - - -
- -*Successfully retrieved Broker Configuration view* - -
-
- -#### Sample request - - - - - - -```shell -curl "http://COORDINATOR_IP:COORDINATOR_PORT/druid/coordinator/v1/brokerConfigurationStatus" -``` - - - - - -```http -GET /druid/coordinator/v1/brokerConfigurationStatus HTTP/1.1 -Host: http://COORDINATOR_IP:COORDINATOR_PORT -``` - - - - -#### Sample response - -
- View the response - -```json -[ - "localhost:8082" -] -``` - -
diff --git a/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java b/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java index b9450f956deb..bbd99f897975 100644 --- a/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java +++ b/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java @@ -32,9 +32,9 @@ import com.google.inject.name.Names; import com.google.inject.util.Providers; import org.apache.druid.client.CachingClusteredClient; +import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.DruidServer; import org.apache.druid.client.ImmutableDruidServer; -import org.apache.druid.client.TestCoordinatorDynamicConfigView; import org.apache.druid.client.TimelineServerView; import org.apache.druid.client.cache.CacheConfig; import org.apache.druid.client.cache.CachePopulatorStats; @@ -72,6 +72,7 @@ import org.apache.druid.server.ClientQuerySegmentWalker; import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.SubqueryGuardrailHelper; +import org.apache.druid.server.coordination.TestCoordinatorClient; import org.apache.druid.server.initialization.ServerConfig; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.server.metrics.SubqueryCountStatsProvider; @@ -95,7 +96,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.ForkJoinPool; @@ -359,6 +359,7 @@ public void registerServerRemovedCallback(Executor exec, ServerRemovedCallback c } }, + new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()), MapCache.create(100000), jsonMapper, new ForegroundCachePopulator(jsonMapper, new CachePopulatorStats(), -1), @@ -367,8 +368,7 @@ public void registerServerRemovedCallback(Executor exec, ServerRemovedCallback c new BrokerParallelMergeConfig(), ForkJoinPool.commonPool(), QueryStackTests.DEFAULT_NOOP_SCHEDULER, - new NoopServiceEmitter(), - new TestCoordinatorDynamicConfigView(Set.of(), Set.of()) + new NoopServiceEmitter() ); ClientQuerySegmentWalker walker = new ClientQuerySegmentWalker( diff --git a/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java similarity index 89% rename from server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java rename to server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java index ceeb3214e9f1..05c8c71cf6c5 100644 --- a/server/src/main/java/org/apache/druid/client/CoordinatorDynamicConfigView.java +++ b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java @@ -37,9 +37,9 @@ * This class is registered as a managed lifecycle to fetch the coordinator dynamic configuration on startup. Further * updates are handled through {@link DruidInternalDynamicConfigResource}. */ -public class CoordinatorDynamicConfigView +public class BrokerViewOfCoordinatorConfig { - private static final Logger log = new Logger(CoordinatorDynamicConfigView.class); + private static final Logger log = new Logger(BrokerViewOfCoordinatorConfig.class); private final CoordinatorClient coordinatorClient; @GuardedBy("this") @@ -50,7 +50,7 @@ public class CoordinatorDynamicConfigView private Set serversBeingCloned; @Inject - public CoordinatorDynamicConfigView(CoordinatorClient coordinatorClient) + public BrokerViewOfCoordinatorConfig(CoordinatorClient coordinatorClient) { this.coordinatorClient = coordinatorClient; } @@ -64,9 +64,9 @@ public synchronized CoordinatorDynamicConfig getDynamicConfiguration() * Update the config view with a new coordinator dynamic config snapshot. Also updates the source and target clone * servers based on the new dynamic configuration. */ - public synchronized void setDynamicConfiguration(@NotNull CoordinatorDynamicConfig updatedConfig) + public synchronized void setDynamicConfig(@NotNull CoordinatorDynamicConfig updatedConfig) { - config = updatedConfig.snapshot(); + config = updatedConfig; final Map cloneServers = config.getCloneServers(); this.cloneServers = ImmutableSet.copyOf(cloneServers.keySet()); this.serversBeingCloned = ImmutableSet.copyOf(cloneServers.values()); @@ -89,7 +89,7 @@ public void start() log.info("Fetching coordinator dynamic configuration."); CoordinatorDynamicConfig coordinatorDynamicConfig = coordinatorClient.getCoordinatorDynamicConfig().get(); - setDynamicConfiguration(coordinatorDynamicConfig); + setDynamicConfig(coordinatorDynamicConfig); log.info("Successfully initialized dynamic config: [%s]", coordinatorDynamicConfig); } diff --git a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java index 1d21d8ff57a9..718716294efe 100644 --- a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java +++ b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java @@ -127,12 +127,13 @@ public class CachingClusteredClient implements QuerySegmentWalker private final ForkJoinPool pool; private final QueryScheduler scheduler; private final ServiceEmitter emitter; - private final CoordinatorDynamicConfigView coordinatorDynamicConfigView; + private final BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig; @Inject public CachingClusteredClient( QueryRunnerFactoryConglomerate conglomerate, TimelineServerView serverView, + BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig, Cache cache, @Smile ObjectMapper objectMapper, CachePopulator cachePopulator, @@ -141,8 +142,7 @@ public CachingClusteredClient( BrokerParallelMergeConfig parallelMergeConfig, @Merging ForkJoinPool pool, QueryScheduler scheduler, - ServiceEmitter emitter, - CoordinatorDynamicConfigView coordinatorDynamicConfigView + ServiceEmitter emitter ) { this.conglomerate = conglomerate; @@ -156,7 +156,7 @@ public CachingClusteredClient( this.pool = pool; this.scheduler = scheduler; this.emitter = emitter; - this.coordinatorDynamicConfigView = coordinatorDynamicConfigView; + this.brokerViewOfCoordinatorConfig = brokerViewOfCoordinatorConfig; if (cacheConfig.isQueryCacheable(Query.GROUP_BY) && (cacheConfig.isUseCache() || cacheConfig.isPopulateCache())) { log.warn( @@ -295,8 +295,7 @@ private class SpecificQueryRunnable query, strategy, useCache, - populateCache, - coordinatorDynamicConfigView + populateCache ); } @@ -349,7 +348,7 @@ ClusterQueryResult run( final Set segmentServers = computeSegmentsToQuery(timeline, specificSegments); final HistoricalFilter historicalFilter = new HistoricalFilter( - coordinatorDynamicConfigView, + brokerViewOfCoordinatorConfig, query.context().getCloneQueryMode() ); @Nullable @@ -790,20 +789,17 @@ static class CacheKeyManager private final Query query; private final CacheStrategy> strategy; private final boolean isSegmentLevelCachingEnable; - private final CoordinatorDynamicConfigView coordinatorDynamicConfigView; CacheKeyManager( final Query query, final CacheStrategy> strategy, final boolean useCache, - final boolean populateCache, - final CoordinatorDynamicConfigView coordinatorDynamicConfigView + final boolean populateCache ) { this.query = query; this.strategy = strategy; - this.coordinatorDynamicConfigView = coordinatorDynamicConfigView; this.isSegmentLevelCachingEnable = ((populateCache || useCache) && !query.context().isBySegment()); // explicit bySegment queries are never cached diff --git a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java index 71514c3f3c88..ab64ac8f4cc9 100644 --- a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java +++ b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java @@ -21,7 +21,7 @@ import com.google.common.collect.ImmutableSet; import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap; -import org.apache.druid.client.CoordinatorDynamicConfigView; +import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.QueryableDruidServer; import org.apache.druid.query.CloneQueryMode; @@ -40,7 +40,7 @@ public HistoricalFilter(Supplier> serversToFilter) this.serversToFilter = serversToFilter; } - public HistoricalFilter(CoordinatorDynamicConfigView configView, CloneQueryMode cloneQueryMode) + public HistoricalFilter(BrokerViewOfCoordinatorConfig configView, CloneQueryMode cloneQueryMode) { this.serversToFilter = () -> { switch (cloneQueryMode) { diff --git a/server/src/main/java/org/apache/druid/discovery/DiscoveryDruidNode.java b/server/src/main/java/org/apache/druid/discovery/DiscoveryDruidNode.java index 36ea317215b0..3a62e5344b11 100644 --- a/server/src/main/java/org/apache/druid/discovery/DiscoveryDruidNode.java +++ b/server/src/main/java/org/apache/druid/discovery/DiscoveryDruidNode.java @@ -31,7 +31,6 @@ import org.apache.druid.java.util.common.IAE; import org.apache.druid.java.util.common.NonnullPair; import org.apache.druid.java.util.common.logger.Logger; -import org.apache.druid.rpc.ServiceLocation; import org.apache.druid.server.DruidNode; import org.joda.time.DateTime; @@ -201,21 +200,6 @@ public T getService(String key, Class clazz) return null; } - public ServiceLocation toServiceLocation() - { - final DruidNode druidNode = getDruidNode(); - if (druidNode == null) { - return null; - } - - return new ServiceLocation( - druidNode.getHost(), - druidNode.getPlaintextPort(), - druidNode.getTlsPort(), - "" - ); - } - public DruidServer toDruidServer() { final DataNodeService dataNodeService = getService( diff --git a/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java b/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java index f58243bedc16..e3b122aa489d 100644 --- a/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java +++ b/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java @@ -23,7 +23,7 @@ import com.fasterxml.jackson.jaxrs.smile.SmileMediaTypes; import com.google.inject.Inject; import com.sun.jersey.spi.container.ResourceFilters; -import org.apache.druid.client.CoordinatorDynamicConfigView; +import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.ServerViewUtil; import org.apache.druid.client.TimelineServerView; import org.apache.druid.client.selector.HistoricalFilter; @@ -58,7 +58,7 @@ public class BrokerQueryResource extends QueryResource { private final TimelineServerView brokerServerView; - private final CoordinatorDynamicConfigView configView; + private final BrokerViewOfCoordinatorConfig configView; @Inject public BrokerQueryResource( @@ -71,7 +71,7 @@ public BrokerQueryResource( ResponseContextConfig responseContextConfig, @Self DruidNode selfNode, TimelineServerView brokerServerView, - CoordinatorDynamicConfigView configView + BrokerViewOfCoordinatorConfig configView ) { super( @@ -97,15 +97,21 @@ public Response getQueryTargets( InputStream in, @QueryParam("pretty") String pretty, @QueryParam("numCandidates") @DefaultValue("-1") int numCandidates, - @QueryParam("cloneQueryMode") @Nullable CloneQueryMode cloneQueryMode, + @QueryParam("cloneQueryMode") @Nullable String cloneQueryModeString, @Context final HttpServletRequest req ) throws IOException { final ResourceIOReaderWriter ioReaderWriter = createResourceIOReaderWriter(req, pretty != null); + final CloneQueryMode cloneQueryMode = QueryContexts.getAsEnum( + QueryContexts.CLONE_QUERY_MODE, + cloneQueryModeString, + CloneQueryMode.class, + QueryContexts.DEFAULT_CLONE_QUERY_MODE + ); try { Query query = ioReaderWriter.getRequestMapper().readValue(in, Query.class); ExecutionVertex ev = ExecutionVertex.of(query); - HistoricalFilter historicalFilter = new HistoricalFilter(configView, cloneQueryMode == null ? QueryContexts.DEFAULT_CLONE_QUERY_MODE : cloneQueryMode); + HistoricalFilter historicalFilter = new HistoricalFilter(configView, cloneQueryMode); return ioReaderWriter.getResponseWriter().ok( ServerViewUtil.getTargetLocations( brokerServerView, diff --git a/server/src/main/java/org/apache/druid/server/ClientInfoResource.java b/server/src/main/java/org/apache/druid/server/ClientInfoResource.java index aff2939341d6..50099a21d1c4 100644 --- a/server/src/main/java/org/apache/druid/server/ClientInfoResource.java +++ b/server/src/main/java/org/apache/druid/server/ClientInfoResource.java @@ -25,7 +25,7 @@ import com.google.common.collect.Maps; import com.google.inject.Inject; import com.sun.jersey.spi.container.ResourceFilters; -import org.apache.druid.client.CoordinatorDynamicConfigView; +import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.DruidDataSource; import org.apache.druid.client.FilteredServerInventoryView; import org.apache.druid.client.ServerViewUtil; @@ -38,6 +38,7 @@ import org.apache.druid.java.util.common.logger.Logger; import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.LocatedSegmentDescriptor; +import org.apache.druid.query.QueryContexts; import org.apache.druid.query.TableDataSource; import org.apache.druid.query.metadata.SegmentMetadataQueryConfig; import org.apache.druid.server.http.security.DatasourceResourceFilter; @@ -52,6 +53,7 @@ import org.joda.time.DateTime; import org.joda.time.Interval; +import javax.annotation.Nullable; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; @@ -89,16 +91,16 @@ public class ClientInfoResource private SegmentMetadataQueryConfig segmentMetadataQueryConfig; private final AuthConfig authConfig; private final AuthorizerMapper authorizerMapper; - private final CoordinatorDynamicConfigView configView; + private final BrokerViewOfCoordinatorConfig configView; @Inject public ClientInfoResource( FilteredServerInventoryView serverInventoryView, TimelineServerView timelineServerView, + BrokerViewOfCoordinatorConfig configView, SegmentMetadataQueryConfig segmentMetadataQueryConfig, AuthConfig authConfig, - AuthorizerMapper authorizerMapper, - CoordinatorDynamicConfigView configView + AuthorizerMapper authorizerMapper ) { this.serverInventoryView = serverInventoryView; @@ -306,10 +308,16 @@ public Iterable getQueryTargets( @PathParam("dataSourceName") String datasource, @QueryParam("intervals") String intervals, @QueryParam("numCandidates") @DefaultValue("-1") int numCandidates, - @QueryParam("cloneQueryMode") CloneQueryMode cloneQueryMode, + @QueryParam("cloneQueryMode") @Nullable String cloneQueryModeString, @Context final HttpServletRequest req ) { + final CloneQueryMode cloneQueryMode = QueryContexts.getAsEnum( + QueryContexts.CLONE_QUERY_MODE, + cloneQueryModeString, + CloneQueryMode.class, + QueryContexts.DEFAULT_CLONE_QUERY_MODE + ); List intervalList = new ArrayList<>(); for (String interval : intervals.split(",")) { intervalList.add(Intervals.of(interval.trim())); diff --git a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java index c979963f7393..a62695e56d04 100644 --- a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java +++ b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java @@ -21,7 +21,7 @@ import com.google.inject.Inject; import com.sun.jersey.spi.container.ResourceFilters; -import org.apache.druid.client.CoordinatorDynamicConfigView; +import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import org.apache.druid.server.http.security.ConfigResourceFilter; @@ -33,33 +33,33 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -@Path("/druid-internal/v1/dynamicConfiguration") +@Path("/druid-internal/v1/config") public class DruidInternalDynamicConfigResource { - private final CoordinatorDynamicConfigView coordinatorDynamicConfigView; + private final BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig; @Inject - public DruidInternalDynamicConfigResource(CoordinatorDynamicConfigView coordinatorDynamicConfigView) + public DruidInternalDynamicConfigResource(BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig) { - this.coordinatorDynamicConfigView = coordinatorDynamicConfigView; + this.brokerViewOfCoordinatorConfig = brokerViewOfCoordinatorConfig; } @GET @Produces(MediaType.APPLICATION_JSON) @ResourceFilters(ConfigResourceFilter.class) - @Path("/coordinatorDynamicConfig") + @Path("/coordinator") public Response getDynamicConfig() { - return Response.ok(coordinatorDynamicConfigView.getDynamicConfiguration()).build(); + return Response.ok(brokerViewOfCoordinatorConfig.getDynamicConfiguration()).build(); } @POST @Consumes(MediaType.APPLICATION_JSON) @ResourceFilters(ConfigResourceFilter.class) - @Path("/coordinatorDynamicConfig") + @Path("/coordinator") public Response setDynamicConfig(final CoordinatorDynamicConfig dynamicConfig) { - coordinatorDynamicConfigView.setDynamicConfiguration(dynamicConfig); + brokerViewOfCoordinatorConfig.setDynamicConfig(dynamicConfig); return Response.ok("OK").build(); } } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java index 9945c58320f7..c0583be46988 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java @@ -23,32 +23,34 @@ import org.apache.druid.server.coordinator.loading.SegmentAction; import org.apache.druid.timeline.DataSegment; +import javax.annotation.Nullable; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; public class CloneStatusManager { - private final AtomicReference> cloneStatusSnapshot; + private final AtomicReference> cloneStatusSnapshot; public CloneStatusManager() { - this.cloneStatusSnapshot = new AtomicReference<>(ImmutableMap.of()); + this.cloneStatusSnapshot = new AtomicReference<>(Map.of()); } - public Map getStatusForAllServers() + public Map getStatusForAllServers() { return cloneStatusSnapshot.get(); } - public CloneStatusMetrics getStatusForServer(String targetServer) + @Nullable + public ServerCloneStatus getStatusForServer(String targetServer) { return cloneStatusSnapshot.get().get(targetServer); } - public void updateStats(Map historicalMap, Map cloneServers) + public void updateStatus(Map historicalMap, Map cloneServers) { - final Map newStatusMap = new HashMap<>(); + final Map newStatusMap = new HashMap<>(); for (Map.Entry entry : cloneServers.entrySet()) { final String targetServerName = entry.getKey(); @@ -59,16 +61,16 @@ public void updateStats(Map historicalMap, Map queuedSegment : targetServer.getQueuedSegments().entrySet()) { @@ -79,7 +81,7 @@ public void updateStats(Map historicalMap, Map validateDebugDimensions(Map debug return validDebugDimensions; } - public CoordinatorDynamicConfig snapshot() - { - return new CoordinatorDynamicConfig( - markSegmentAsUnusedDelayMillis, - maxSegmentsToMove, - replicantLifetime, - replicationThrottleLimit, - balancerComputeThreads, - specificDataSourcesToKillUnusedSegmentsIn != null ? ImmutableSet.copyOf(specificDataSourcesToKillUnusedSegmentsIn) : null, - killTaskSlotRatio, - maxKillTaskSlots, - dataSourcesToNotKillStalePendingSegmentsIn != null ? ImmutableSet.copyOf(dataSourcesToNotKillStalePendingSegmentsIn) : null, - maxSegmentsInNodeLoadingQueue, - decommissioningNodes != null ? ImmutableSet.copyOf(decommissioningNodes) : null, - pauseCoordination, - replicateAfterLoadTimeout, - useRoundRobinSegmentAssignment, - smartSegmentLoading, - debugDimensions != null ? ImmutableMap.copyOf(debugDimensions) : null, - turboLoadingNodes != null ? ImmutableSet.copyOf(turboLoadingNodes) : null, - cloneServers != null ? ImmutableMap.copyOf(cloneServers) : null - ); - } - private static Set parseJsonStringOrArray(Object jsonStringOrArray) { if (jsonStringOrArray instanceof String) { diff --git a/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java b/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java index af0e07c99c4b..c79ae92eb055 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java @@ -63,7 +63,6 @@ import org.apache.druid.server.coordinator.config.DruidCoordinatorConfig; import org.apache.druid.server.coordinator.config.KillUnusedSegmentsConfig; import org.apache.druid.server.coordinator.duty.BalanceSegments; -import org.apache.druid.server.coordinator.duty.BrokerDynamicConfigSync; import org.apache.druid.server.coordinator.duty.CloneHistoricals; import org.apache.druid.server.coordinator.duty.CompactSegments; import org.apache.druid.server.coordinator.duty.CoordinatorCustomDutyGroup; @@ -84,6 +83,7 @@ import org.apache.druid.server.coordinator.duty.MetadataAction; import org.apache.druid.server.coordinator.duty.PrepareBalancerAndLoadQueues; import org.apache.druid.server.coordinator.duty.RunRules; +import org.apache.druid.server.coordinator.duty.SendDynamicConfigToBrokers; import org.apache.druid.server.coordinator.duty.UnloadUnusedSegments; import org.apache.druid.server.coordinator.loading.LoadQueuePeon; import org.apache.druid.server.coordinator.loading.LoadQueueTaskMaster; @@ -568,7 +568,7 @@ private List makeHistoricalManagementDuties() new MarkEternityTombstonesAsUnused(deleteSegments), new BalanceSegments(config.getCoordinatorPeriod()), new CloneHistoricals(loadQueueManager, cloneStatusManager), - new BrokerDynamicConfigSync(coordinatorDynamicConfigSyncer), + new SendDynamicConfigToBrokers(coordinatorDynamicConfigSyncer), new CollectLoadQueueStats() ); } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java b/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java similarity index 67% rename from server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java rename to server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java index 803b4bdcdd47..deb1ff43ad26 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusMetrics.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java @@ -24,63 +24,63 @@ import java.util.Objects; -public class CloneStatusMetrics +public class ServerCloneStatus { private final String sourceServer; - private final Status status; + private final State state; private final long segmentLoadsRemaining; - private final long segmenetsDropsRemaining; + private final long segmentDropsRemaining; private final long bytesRemaining; @JsonCreator - public CloneStatusMetrics( + public ServerCloneStatus( @JsonProperty("sourceServer") String sourceServer, - @JsonProperty("status") Status status, + @JsonProperty("state") State state, @JsonProperty("segmentLoadsRemaining") long segmentLoadsRemaining, - @JsonProperty("segmentDropsRemaining") long segmenetsDropsRemaining, + @JsonProperty("segmentDropsRemaining") long segmentDropsRemaining, @JsonProperty("bytesRemaining") long bytesRemaining ) { this.sourceServer = sourceServer; - this.status = status; + this.state = state; this.segmentLoadsRemaining = segmentLoadsRemaining; - this.segmenetsDropsRemaining = segmenetsDropsRemaining; + this.segmentDropsRemaining = segmentDropsRemaining; this.bytesRemaining = bytesRemaining; } - @JsonProperty("sourceServer") + @JsonProperty public String getSourceServer() { return sourceServer; } - @JsonProperty("segmentLoadsRemaining") + @JsonProperty public long getSegmentLoadsRemaining() { return segmentLoadsRemaining; } - @JsonProperty("segmentDropsRemaining") - public long getSegmenetsDropsRemaining() + @JsonProperty + public long getSegmentDropsRemaining() { - return segmenetsDropsRemaining; + return segmentDropsRemaining; } - @JsonProperty("bytesRemaining") + @JsonProperty public long getBytesRemaining() { return bytesRemaining; } - @JsonProperty("status") - public Status getStatus() + @JsonProperty + public State getState() { - return status; + return state; } - public static CloneStatusMetrics unknown(String sourceServer) + public static ServerCloneStatus unknown(String sourceServer) { - return new CloneStatusMetrics(sourceServer, Status.TARGET_SERVER_MISSING, 0, 0, 0); + return new ServerCloneStatus(sourceServer, State.TARGET_SERVER_MISSING, 0, 0, 0); } @Override @@ -92,18 +92,18 @@ public boolean equals(Object o) if (o == null || getClass() != o.getClass()) { return false; } - CloneStatusMetrics that = (CloneStatusMetrics) o; + ServerCloneStatus that = (ServerCloneStatus) o; return segmentLoadsRemaining == that.segmentLoadsRemaining - && segmenetsDropsRemaining == that.segmenetsDropsRemaining + && segmentDropsRemaining == that.segmentDropsRemaining && bytesRemaining == that.bytesRemaining && Objects.equals(sourceServer, that.sourceServer) - && status == that.status; + && state == that.state; } @Override public int hashCode() { - return Objects.hash(sourceServer, status, segmentLoadsRemaining, segmenetsDropsRemaining, bytesRemaining); + return Objects.hash(sourceServer, state, segmentLoadsRemaining, segmentDropsRemaining, bytesRemaining); } @Override @@ -111,9 +111,9 @@ public String toString() { return "CloneStatusMetrics{" + "sourceServer='" + sourceServer + '\'' + - ", status=" + status + + ", state=" + state + ", segmentLoadsRemaining=" + segmentLoadsRemaining + - ", segmenetsDropsRemaining=" + segmenetsDropsRemaining + + ", segmentDropsRemaining=" + segmentDropsRemaining + ", bytesRemaining=" + bytesRemaining + '}'; } @@ -121,7 +121,7 @@ public String toString() /** * Enum determining the status of the cloning process. */ - public enum Status + public enum State { SOURCE_SERVER_MISSING, TARGET_SERVER_MISSING, diff --git a/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java b/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java index b377829f12f1..9b1311084058 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java @@ -121,7 +121,7 @@ public DruidCoordinatorRuntimeParams run(DruidCoordinatorRuntimeParams params) } } - cloneStatusManager.updateStats(hostToHistorical, cloneServers); + cloneStatusManager.updateStatus(hostToHistorical, cloneServers); return params; } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/duty/BrokerDynamicConfigSync.java b/server/src/main/java/org/apache/druid/server/coordinator/duty/SendDynamicConfigToBrokers.java similarity index 89% rename from server/src/main/java/org/apache/druid/server/coordinator/duty/BrokerDynamicConfigSync.java rename to server/src/main/java/org/apache/druid/server/coordinator/duty/SendDynamicConfigToBrokers.java index a39a4166886a..cd2cf944208c 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/duty/BrokerDynamicConfigSync.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/duty/SendDynamicConfigToBrokers.java @@ -25,11 +25,11 @@ /** * Duty to periodically broadcast the coordinator dynamic configuration to all brokers. */ -public class BrokerDynamicConfigSync implements CoordinatorDuty +public class SendDynamicConfigToBrokers implements CoordinatorDuty { private final CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer; - public BrokerDynamicConfigSync(CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer) + public SendDynamicConfigToBrokers(CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer) { this.coordinatorDynamicConfigSyncer = coordinatorDynamicConfigSyncer; } diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java index 92bbd655cefc..9b8c5088ecc0 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java @@ -37,11 +37,13 @@ import org.apache.druid.rpc.ServiceClientFactory; import org.apache.druid.rpc.ServiceLocation; import org.apache.druid.rpc.StandardRetryPolicy; +import org.apache.druid.server.DruidNode; import org.apache.druid.server.coordinator.CoordinatorConfigManager; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpResponseStatus; +import javax.annotation.Nullable; import java.net.URL; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -84,9 +86,11 @@ public CoordinatorDynamicConfigSyncer( public void broadcastConfigToBrokers() { invalidateInSyncBrokersIfNeeded(); - for (ServiceLocation broker : getKnownBrokers()) { - exec.submit(() -> pushConfigToBroker(broker)); - } + exec.submit(() -> { + for (ServiceLocation broker : getKnownBrokers()) { + pushConfigToBroker(broker); + } + }); } public synchronized Set getInSyncBrokers() @@ -105,13 +109,13 @@ private void pushConfigToBroker(ServiceLocation brokerLocation) try { CoordinatorDynamicConfig currentDynamicConfig = configManager.getCurrentDynamicConfig(); final RequestBuilder requestBuilder = - new RequestBuilder(HttpMethod.POST, "/druid-internal/v1/dynamicConfiguration/coordinatorDynamicConfig") + new RequestBuilder(HttpMethod.POST, "/druid-internal/v1/config/coordinator") .jsonContent(jsonMapper, currentDynamicConfig); final BytesFullResponseHolder responseHolder = brokerClient.request(requestBuilder, new BytesFullResponseHandler()); final HttpResponseStatus status = responseHolder.getStatus(); if (status.equals(HttpResponseStatus.OK)) { - addToInSyncBrokers(currentDynamicConfig, brokerLocation); + markBrokerAsSynced(currentDynamicConfig, brokerLocation); } else { log.error( "Received status [%s] while posting dynamic configs to broker[%s]", @@ -135,7 +139,7 @@ private Set getKnownBrokers() return druidNodeDiscovery.getForNodeRole(NodeRole.BROKER) .getAllNodes() .stream() - .map(DiscoveryDruidNode::toServiceLocation) + .map(CoordinatorDynamicConfigSyncer::convertDiscoveryNodeToServiceLocation) .collect(Collectors.toSet()); } @@ -149,11 +153,27 @@ private synchronized void invalidateInSyncBrokersIfNeeded() } } - private synchronized void addToInSyncBrokers(CoordinatorDynamicConfig config, ServiceLocation broker) + private synchronized void markBrokerAsSynced(CoordinatorDynamicConfig config, ServiceLocation broker) { final URL url = broker.toURL(""); if (config.equals(lastKnownConfig.get())) { inSyncBrokers.add(StringUtils.format("%s:%s", url.getHost(), url.getPort())); } } + + @Nullable + private static ServiceLocation convertDiscoveryNodeToServiceLocation(DiscoveryDruidNode discoveryDruidNode) + { + final DruidNode druidNode = discoveryDruidNode.getDruidNode(); + if (druidNode == null) { + return null; + } + + return new ServiceLocation( + druidNode.getHost(), + druidNode.getPlaintextPort(), + druidNode.getTlsPort(), + "" + ); + } } diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java index 23f857bbad61..f0738343da7b 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java @@ -19,16 +19,21 @@ package org.apache.druid.server.http; +import com.google.common.collect.ImmutableMap; import com.sun.jersey.spi.container.ResourceFilters; import org.apache.druid.audit.AuditManager; import org.apache.druid.common.config.ConfigManager.SetResult; import org.apache.druid.java.util.common.Intervals; +import org.apache.druid.server.coordinator.CloneStatusManager; import org.apache.druid.server.coordinator.CoordinatorConfigManager; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; +import org.apache.druid.server.coordinator.ServerCloneStatus; import org.apache.druid.server.http.security.ConfigResourceFilter; +import org.apache.druid.server.http.security.StateResourceFilter; import org.apache.druid.server.security.AuthorizationUtils; import org.joda.time.Interval; +import javax.annotation.Nullable; import javax.inject.Inject; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; @@ -50,17 +55,20 @@ public class CoordinatorDynamicConfigsResource private final CoordinatorConfigManager manager; private final AuditManager auditManager; private final CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer; + private final CloneStatusManager cloneStatusManager; @Inject public CoordinatorDynamicConfigsResource( CoordinatorConfigManager manager, AuditManager auditManager, - CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer + CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer, + CloneStatusManager cloneStatusManager ) { this.manager = manager; this.auditManager = auditManager; this.coordinatorDynamicConfigSyncer = coordinatorDynamicConfigSyncer; + this.cloneStatusManager = cloneStatusManager; } @GET @@ -136,4 +144,26 @@ public Response getDatasourceRuleHistory( ).build(); } + @GET + @Path("/syncedBrokers") + @ResourceFilters(StateResourceFilter.class) + @Produces(MediaType.APPLICATION_JSON) + public Response getBrokerStatus() + { + return Response.ok(coordinatorDynamicConfigSyncer.getInSyncBrokers()).build(); + } + + @GET + @Path("/cloneStatus") + @ResourceFilters(StateResourceFilter.class) + @Produces(MediaType.APPLICATION_JSON) + public Response getCloneStatus(@QueryParam("targetServer") @Nullable String targetServer) + { + if (targetServer != null) { + ServerCloneStatus statusForServer = cloneStatusManager.getStatusForServer(targetServer); + return Response.ok(ImmutableMap.of(targetServer, statusForServer)).build(); + } else { + return Response.ok(cloneStatusManager.getStatusForAllServers()).build(); + } + } } diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java index 64be2e6ed996..1f61464bafbf 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorResource.java @@ -24,8 +24,6 @@ import com.google.common.collect.Maps; import com.google.inject.Inject; import com.sun.jersey.spi.container.ResourceFilters; -import org.apache.druid.server.coordinator.CloneStatusManager; -import org.apache.druid.server.coordinator.CloneStatusMetrics; import org.apache.druid.server.coordinator.DruidCoordinator; import org.apache.druid.server.http.security.StateResourceFilter; import org.apache.druid.timeline.DataSegment; @@ -45,15 +43,11 @@ public class CoordinatorResource { private final DruidCoordinator coordinator; - private final CloneStatusManager cloneStatusManager; - private final CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer; @Inject - public CoordinatorResource(DruidCoordinator coordinator, CloneStatusManager cloneStatusManager, CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer) + public CoordinatorResource(DruidCoordinator coordinator) { this.coordinator = coordinator; - this.cloneStatusManager = cloneStatusManager; - this.coordinatorDynamicConfigSyncer = coordinatorDynamicConfigSyncer; } @GET @@ -164,28 +158,4 @@ public Response getStatusOfDuties() { return Response.ok(new CoordinatorDutyStatus(coordinator.getStatusOfDuties())).build(); } - - @GET - @Path("/brokerConfigurationStatus") - @ResourceFilters(StateResourceFilter.class) - @Produces(MediaType.APPLICATION_JSON) - public Response getBrokerStatus() - { - return Response.ok(coordinatorDynamicConfigSyncer.getInSyncBrokers()).build(); - } - - @GET - @Path("/cloneStatus") - @ResourceFilters(StateResourceFilter.class) - @Produces(MediaType.APPLICATION_JSON) - public Response getCloneStatus(@QueryParam("targetServer") @Nullable String targetServer) - { - if (targetServer != null) { - CloneStatusMetrics statusForServer = cloneStatusManager.getStatusForServer(targetServer); - return Response.ok(ImmutableMap.of(targetServer, statusForServer)).build(); - - } else { - return Response.ok(cloneStatusManager.getStatusForAllServers()).build(); - } - } } diff --git a/server/src/test/java/org/apache/druid/client/CoordinatorDynamicConfigViewTest.java b/server/src/test/java/org/apache/druid/client/BrokerViewOfCoordinatorConfigTest.java similarity index 91% rename from server/src/test/java/org/apache/druid/client/CoordinatorDynamicConfigViewTest.java rename to server/src/test/java/org/apache/druid/client/BrokerViewOfCoordinatorConfigTest.java index 244698dffaf9..907a3745ea3b 100644 --- a/server/src/test/java/org/apache/druid/client/CoordinatorDynamicConfigViewTest.java +++ b/server/src/test/java/org/apache/druid/client/BrokerViewOfCoordinatorConfigTest.java @@ -30,9 +30,9 @@ import java.util.Map; import java.util.Set; -public class CoordinatorDynamicConfigViewTest +public class BrokerViewOfCoordinatorConfigTest { - private CoordinatorDynamicConfigView target; + private BrokerViewOfCoordinatorConfig target; private CoordinatorClient coordinatorClient; private CoordinatorDynamicConfig config; @@ -46,7 +46,7 @@ public void setUp() throws Exception .build(); coordinatorClient = Mockito.mock(CoordinatorClient.class); Mockito.when(coordinatorClient.getCoordinatorDynamicConfig()).thenReturn(Futures.immediateFuture(config)); - target = new CoordinatorDynamicConfigView(coordinatorClient); + target = new BrokerViewOfCoordinatorConfig(coordinatorClient); } @Test @@ -64,7 +64,7 @@ public void testCreatesServerLists() .withCloneServers(Map.of("host1", "host2", "host4", "host5")) .build(); - target.setDynamicConfiguration(config); + target.setDynamicConfig(config); Assert.assertEquals(Set.of("host1", "host4"), target.getClones()); Assert.assertEquals(Set.of("host2", "host5"), target.getServersBeingCloned()); diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java index d7f6025a106f..d3ef6960b382 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java @@ -201,8 +201,7 @@ public void testComputeEtag_noEffectIfUseAndPopulateFalse() query, strategy, false, - false, - null + false ); Set selectors = ImmutableSet.of( makeHistoricalServerSelector(1), @@ -261,8 +260,7 @@ public void testSegmentQueryCacheKey_useAndPopulateCacheFalse() query, strategy, false, - false, - null + false ).computeSegmentLevelQueryCacheKey()); } @@ -272,8 +270,7 @@ private CachingClusteredClient.CacheKeyManager makeKeyManager() query, strategy, true, - true, - null + true ); } diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java index 8b7837924aa8..850a82b292e8 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java @@ -45,6 +45,7 @@ import org.apache.druid.query.context.ResponseContext; import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.coordination.ServerType; +import org.apache.druid.server.coordination.TestCoordinatorClient; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.TimelineLookup; @@ -268,6 +269,7 @@ public void registerServerRemovedCallback(Executor exec, ServerRemovedCallback c } }, + new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()), cache, OBJECT_MAPPER, cachePopulator, @@ -329,8 +331,7 @@ public int getDefaultMaxQueryParallelism() }, ForkJoinPool.commonPool(), QueryStackTests.DEFAULT_NOOP_SCHEDULER, - new NoopServiceEmitter(), - new TestCoordinatorDynamicConfigView(Set.of(), Set.of()) + new NoopServiceEmitter() ); } diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java index 9699d88ca842..c7509a2168ab 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java @@ -53,6 +53,7 @@ import org.apache.druid.server.QueryScheduler; import org.apache.druid.server.coordination.ServerManagerTest; import org.apache.druid.server.coordination.ServerType; +import org.apache.druid.server.coordination.TestCoordinatorClient; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.VersionedIntervalTimeline; @@ -67,7 +68,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.concurrent.ForkJoinPool; import static org.mockito.ArgumentMatchers.any; @@ -132,6 +132,7 @@ public void testGetQueryRunnerForSegments_singleIntervalLargeSegments() CachingClusteredClient cachingClusteredClient = new CachingClusteredClient( new MockQueryRunnerFactoryConglomerate(), serverView, + new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()), MapCache.create(1024), TestHelper.makeJsonMapper(), Mockito.mock(CachePopulator.class), @@ -140,8 +141,7 @@ public void testGetQueryRunnerForSegments_singleIntervalLargeSegments() Mockito.mock(BrokerParallelMergeConfig.class), ForkJoinPool.commonPool(), queryScheduler, - new NoopServiceEmitter(), - new TestCoordinatorDynamicConfigView(Set.of(), Set.of()) + new NoopServiceEmitter() ); Query fakeQuery = makeFakeQuery(interval); diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java index c82c6e4ea480..52f9414d63f9 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java @@ -115,6 +115,7 @@ import org.apache.druid.server.QueryScheduler; import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.coordination.ServerType; +import org.apache.druid.server.coordination.TestCoordinatorClient; import org.apache.druid.server.initialization.ServerConfig; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.server.scheduling.ManualQueryPrioritizationStrategy; @@ -2643,6 +2644,7 @@ public void registerServerRemovedCallback(Executor exec, ServerRemovedCallback c } }, + new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()), cache, JSON_MAPPER, cachePopulator, @@ -2709,8 +2711,7 @@ public int getDefaultMaxQueryParallelism() NoQueryLaningStrategy.INSTANCE, new ServerConfig() ), - new NoopServiceEmitter(), - new TestCoordinatorDynamicConfigView(Set.of(), Set.of()) + new NoopServiceEmitter() ); } diff --git a/server/src/test/java/org/apache/druid/client/TestCoordinatorDynamicConfigView.java b/server/src/test/java/org/apache/druid/client/TestCoordinatorDynamicConfigView.java deleted file mode 100644 index 909e88b4a489..000000000000 --- a/server/src/test/java/org/apache/druid/client/TestCoordinatorDynamicConfigView.java +++ /dev/null @@ -1,50 +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.client; - -import java.util.Set; - -public class TestCoordinatorDynamicConfigView extends CoordinatorDynamicConfigView -{ - private final Set targetServers; - private final Set sourceServers; - - public TestCoordinatorDynamicConfigView( - Set targetServers, - Set sourceServers - ) - { - super(null); - this.targetServers = targetServers; - this.sourceServers = sourceServers; - } - - @Override - public synchronized Set getServersBeingCloned() - { - return targetServers; - } - - @Override - public synchronized Set getClones() - { - return sourceServers; - } -} diff --git a/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java b/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java index 31e64957a749..1e62b29976e0 100644 --- a/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java +++ b/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java @@ -23,11 +23,11 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.CachingClusteredClient; import org.apache.druid.client.DirectDruidClient; import org.apache.druid.client.DruidServer; import org.apache.druid.client.SimpleServerView; -import org.apache.druid.client.TestCoordinatorDynamicConfigView; import org.apache.druid.client.TestHttpClient; import org.apache.druid.client.TestHttpClient.SimpleServerManager; import org.apache.druid.client.cache.CacheConfig; @@ -51,6 +51,7 @@ import org.apache.druid.segment.generator.GeneratorSchemaInfo; import org.apache.druid.segment.generator.SegmentGenerator; import org.apache.druid.server.QueryStackTests; +import org.apache.druid.server.coordination.TestCoordinatorClient; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.partition.NumberedShardSpec; @@ -62,7 +63,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Set; import java.util.UUID; import java.util.concurrent.ForkJoinPool; import java.util.stream.Collectors; @@ -126,6 +126,7 @@ public void setupTestBase() cachingClusteredClient = new CachingClusteredClient( conglomerate, simpleServerView, + new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()), MapCache.create(0), objectMapper, new ForegroundCachePopulator(objectMapper, new CachePopulatorStats(), 0), @@ -134,8 +135,7 @@ public void setupTestBase() QueryStackTests.getParallelMergeConfig(USE_PARALLEL_MERGE_POOL_CONFIGURED), ForkJoinPool.commonPool(), QueryStackTests.DEFAULT_NOOP_SCHEDULER, - new NoopServiceEmitter(), - new TestCoordinatorDynamicConfigView(Set.of(), Set.of()) + new NoopServiceEmitter() ); servers = new ArrayList<>(); } diff --git a/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java b/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java index c810e5c2d1c3..43f62f94175f 100644 --- a/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java @@ -405,9 +405,9 @@ private ClientInfoResource getResourceTestHelper( return new ClientInfoResource( serverInventoryView, timelineServerView, + null, segmentMetadataQueryConfig, new AuthConfig(), - null, null ) { diff --git a/server/src/test/java/org/apache/druid/server/coordination/TestCoordinatorClient.java b/server/src/test/java/org/apache/druid/server/coordination/TestCoordinatorClient.java index 9f297ddd39eb..d9dc42aadae5 100644 --- a/server/src/test/java/org/apache/druid/server/coordination/TestCoordinatorClient.java +++ b/server/src/test/java/org/apache/druid/server/coordination/TestCoordinatorClient.java @@ -24,23 +24,31 @@ import org.apache.druid.client.BootstrapSegmentsResponse; import org.apache.druid.client.coordinator.NoopCoordinatorClient; import org.apache.druid.java.util.common.CloseableIterators; +import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import org.apache.druid.timeline.DataSegment; import java.util.HashSet; import java.util.Set; -class TestCoordinatorClient extends NoopCoordinatorClient +public class TestCoordinatorClient extends NoopCoordinatorClient { private final Set bootstrapSegments; + private final CoordinatorDynamicConfig config; - TestCoordinatorClient() + public TestCoordinatorClient() { - this(new HashSet<>()); + this(new HashSet<>(), CoordinatorDynamicConfig.builder().build()); } - TestCoordinatorClient(final Set bootstrapSegments) + public TestCoordinatorClient(final Set bootstrapSegments) + { + this(bootstrapSegments, CoordinatorDynamicConfig.builder().build()); + } + + public TestCoordinatorClient(final Set bootstrapSegments, final CoordinatorDynamicConfig config) { this.bootstrapSegments = bootstrapSegments; + this.config = config; } @Override @@ -50,4 +58,10 @@ public ListenableFuture fetchBootstrapSegments() new BootstrapSegmentsResponse(CloseableIterators.withEmptyBaggage(bootstrapSegments.iterator())) ); } + + @Override + public ListenableFuture getCoordinatorDynamicConfig() + { + return Futures.immediateFuture(config); + } } diff --git a/server/src/test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java b/server/src/test/java/org/apache/druid/server/coordinator/ServerCloneStatusTest.java similarity index 77% rename from server/src/test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java rename to server/src/test/java/org/apache/druid/server/coordinator/ServerCloneStatusTest.java index e9752ab07e3c..0bb299e0bec8 100644 --- a/server/src/test/java/org/apache/druid/server/coordinator/CloneStatusMetricsTest.java +++ b/server/src/test/java/org/apache/druid/server/coordinator/ServerCloneStatusTest.java @@ -24,22 +24,22 @@ import org.junit.Assert; import org.junit.Test; -public class CloneStatusMetricsTest +public class ServerCloneStatusTest { @Test public void testSerde() throws Exception { - CloneStatusMetrics metrics = new CloneStatusMetrics("host2", CloneStatusMetrics.Status.LOADING, 3012, 10, 100); + ServerCloneStatus metrics = new ServerCloneStatus("host2", ServerCloneStatus.State.LOADING, 3012, 10, 100); byte[] bytes = DefaultObjectMapper.INSTANCE.writeValueAsBytes(metrics); - CloneStatusMetrics deserialized = DefaultObjectMapper.INSTANCE.readValue(bytes, CloneStatusMetrics.class); + ServerCloneStatus deserialized = DefaultObjectMapper.INSTANCE.readValue(bytes, ServerCloneStatus.class); Assert.assertEquals(deserialized, metrics); } @Test public void testEquals() { - EqualsVerifier.forClass(CloneStatusMetrics.class) - .withNonnullFields("sourceServer", "status") + EqualsVerifier.forClass(ServerCloneStatus.class) + .withNonnullFields("sourceServer", "state") .usingGetClass() .verify(); } diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java index 337e089b9707..22f3ccbdd4db 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigTest.java @@ -591,23 +591,6 @@ public void testTurboLoadingNodes() Assert.assertEquals(SegmentLoadingMode.TURBO, config.getLoadingModeForServer("localhost:8083")); } - @Test - public void testSnapshot() - { - CoordinatorDynamicConfig config = CoordinatorDynamicConfig.builder() - .withMarkSegmentAsUnusedDelayMillis(1) - .withMaxSegmentsToMove(1) - .withReplicantLifetime(2) - .withReplicationThrottleLimit(4) - .withSmartSegmentLoading(true) - .withDecommissioningNodes(Set.of("host1", "host2")) - .withCloneServers(Map.of("host1", "host2")) - .build(); - - CoordinatorDynamicConfig snapshot = config.snapshot(); - Assert.assertEquals(config, snapshot); - } - @Test public void testEqualsAndHashCode() { diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java new file mode 100644 index 000000000000..407bad6009aa --- /dev/null +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java @@ -0,0 +1,98 @@ +/* + * 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.server.http; + +import com.google.common.collect.ImmutableMap; +import org.apache.druid.audit.AuditManager; +import org.apache.druid.server.coordinator.CloneStatusManager; +import org.apache.druid.server.coordinator.CoordinatorConfigManager; +import org.apache.druid.server.coordinator.ServerCloneStatus; +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import javax.ws.rs.core.Response; +import java.util.Map; +import java.util.Set; + +public class CoordinatorDynamicConfigsResourceTest +{ + private CoordinatorConfigManager manager; + private AuditManager auditManager; + private CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer; + private CloneStatusManager cloneStatusManager; + + @Before + public void setUp() throws Exception + { + manager = EasyMock.createStrictMock(CoordinatorConfigManager.class); + auditManager = EasyMock.createStrictMock(AuditManager.class); + coordinatorDynamicConfigSyncer = EasyMock.createStrictMock(CoordinatorDynamicConfigSyncer.class); + cloneStatusManager = EasyMock.createStrictMock(CloneStatusManager.class); + } + + @Test + public void testGetBrokerStatus() + { + EasyMock.expect(coordinatorDynamicConfigSyncer.getInSyncBrokers()).andReturn(Set.of("brok1")).once(); + EasyMock.replay(coordinatorDynamicConfigSyncer); + EasyMock.replay(cloneStatusManager); + + final Response response = new CoordinatorDynamicConfigsResource( + manager, + auditManager, + coordinatorDynamicConfigSyncer, + cloneStatusManager + ).getBrokerStatus(); + + Assert.assertEquals(200, response.getStatus()); + + Assert.assertEquals(Set.of("brok1"), response.getEntity()); + } + + @Test + public void testGetCloneStatus() + { + Map statusMetrics = ImmutableMap.of( + "hist1", new ServerCloneStatus("hist3", ServerCloneStatus.State.LOADING, 2, 0, 1000), + "hist2", ServerCloneStatus.unknown("hist4") + ); + + EasyMock.expect(cloneStatusManager.getStatusForAllServers()).andReturn(statusMetrics).once(); + EasyMock.expect(cloneStatusManager.getStatusForServer("hist2")).andReturn(ServerCloneStatus.unknown("hist4")).once(); + EasyMock.replay(coordinatorDynamicConfigSyncer); + EasyMock.replay(cloneStatusManager); + + CoordinatorDynamicConfigsResource resource = new CoordinatorDynamicConfigsResource( + manager, + auditManager, + coordinatorDynamicConfigSyncer, + cloneStatusManager + ); + Response response = resource.getCloneStatus(null); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals(statusMetrics, response.getEntity()); + + response = resource.getCloneStatus("hist2"); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals(Map.of("hist2", ServerCloneStatus.unknown("hist4")), response.getEntity()); + } +} diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java index cf84b5188fd5..fe56c5c38d1d 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorResourceTest.java @@ -21,8 +21,6 @@ import com.google.common.collect.ImmutableMap; import org.apache.druid.java.util.common.DateTimes; -import org.apache.druid.server.coordinator.CloneStatusManager; -import org.apache.druid.server.coordinator.CloneStatusMetrics; import org.apache.druid.server.coordinator.DruidCoordinator; import org.apache.druid.server.coordinator.duty.DutyGroupStatus; import org.apache.druid.server.coordinator.loading.TestLoadQueuePeon; @@ -37,21 +35,15 @@ import javax.ws.rs.core.Response; import java.util.Collections; import java.util.List; -import java.util.Map; -import java.util.Set; public class CoordinatorResourceTest { private DruidCoordinator mock; - private CloneStatusManager cloneStatusManager; - private CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer; @Before public void setUp() { mock = EasyMock.createStrictMock(DruidCoordinator.class); - cloneStatusManager = EasyMock.createStrictMock(CloneStatusManager.class); - coordinatorDynamicConfigSyncer = EasyMock.createStrictMock(CoordinatorDynamicConfigSyncer.class); } @After @@ -66,7 +58,7 @@ public void testLeader() EasyMock.expect(mock.getCurrentLeader()).andReturn("boz").once(); EasyMock.replay(mock); - final Response response = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).getLeader(); + final Response response = new CoordinatorResource(mock).getLeader(); Assert.assertEquals("boz", response.getEntity()); Assert.assertEquals(200, response.getStatus()); } @@ -79,12 +71,12 @@ public void testIsLeader() EasyMock.replay(mock); // true - final Response response1 = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).isLeader(); + final Response response1 = new CoordinatorResource(mock).isLeader(); Assert.assertEquals(ImmutableMap.of("leader", true), response1.getEntity()); Assert.assertEquals(200, response1.getStatus()); // false - final Response response2 = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).isLeader(); + final Response response2 = new CoordinatorResource(mock).isLeader(); Assert.assertEquals(ImmutableMap.of("leader", false), response2.getEntity()); Assert.assertEquals(404, response2.getStatus()); } @@ -97,7 +89,7 @@ public void testGetLoadStatusSimple() .once(); EasyMock.replay(mock); - final Response response = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).getLoadQueue("true", null); + final Response response = new CoordinatorResource(mock).getLoadQueue("true", null); Assert.assertEquals( ImmutableMap.of( "hist1", @@ -133,7 +125,7 @@ public void testGetStatusOfDuties() ).once(); EasyMock.replay(mock); - final Response response = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).getStatusOfDuties(); + final Response response = new CoordinatorResource(mock).getStatusOfDuties(); Assert.assertEquals(200, response.getStatus()); final Object payload = response.getEntity(); @@ -154,41 +146,4 @@ public void testGetStatusOfDuties() Assert.assertEquals(100L, observedStatus.getAvgRuntimeMillis()); Assert.assertEquals(500L, observedStatus.getAvgRunGapMillis()); } - - @Test - public void testGetBrokerStatus() - { - EasyMock.expect(coordinatorDynamicConfigSyncer.getInSyncBrokers()).andReturn(Set.of("brok1")).once(); - EasyMock.replay(mock); - EasyMock.replay(coordinatorDynamicConfigSyncer); - EasyMock.replay(cloneStatusManager); - - final Response response = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).getBrokerStatus(); - Assert.assertEquals(200, response.getStatus()); - - Assert.assertEquals(Set.of("brok1"), response.getEntity()); - } - - @Test - public void testGetCloneStatus() - { - Map statusMetrics = ImmutableMap.of( - "hist1", new CloneStatusMetrics("hist3", CloneStatusMetrics.Status.LOADING, 2, 0, 1000), - "hist2", CloneStatusMetrics.unknown("hist4") - ); - - EasyMock.expect(cloneStatusManager.getStatusForAllServers()).andReturn(statusMetrics).once(); - EasyMock.expect(cloneStatusManager.getStatusForServer("hist2")).andReturn(CloneStatusMetrics.unknown("hist4")).once(); - EasyMock.replay(mock); - EasyMock.replay(coordinatorDynamicConfigSyncer); - EasyMock.replay(cloneStatusManager); - - Response response = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).getCloneStatus(null); - Assert.assertEquals(200, response.getStatus()); - Assert.assertEquals(statusMetrics, response.getEntity()); - - response = new CoordinatorResource(mock, cloneStatusManager, coordinatorDynamicConfigSyncer).getCloneStatus("hist2"); - Assert.assertEquals(200, response.getStatus()); - Assert.assertEquals(Map.of("hist2", CloneStatusMetrics.unknown("hist4")), response.getEntity()); - } } diff --git a/services/src/main/java/org/apache/druid/cli/CliBroker.java b/services/src/main/java/org/apache/druid/cli/CliBroker.java index d69376b0e477..21c4e933ba4b 100644 --- a/services/src/main/java/org/apache/druid/cli/CliBroker.java +++ b/services/src/main/java/org/apache/druid/cli/CliBroker.java @@ -28,8 +28,8 @@ import com.google.inject.name.Names; import org.apache.druid.client.BrokerSegmentWatcherConfig; import org.apache.druid.client.BrokerServerView; +import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.CachingClusteredClient; -import org.apache.druid.client.CoordinatorDynamicConfigView; import org.apache.druid.client.DirectDruidClientFactory; import org.apache.druid.client.HttpServerInventoryViewResource; import org.apache.druid.client.InternalQueryConfig; @@ -170,7 +170,7 @@ protected List getModules() LifecycleModule.register(binder, Server.class); binder.bind(SegmentManager.class).in(LazySingleton.class); - binder.bind(CoordinatorDynamicConfigView.class).in(ManageLifecycle.class); + binder.bind(BrokerViewOfCoordinatorConfig.class).in(ManageLifecycle.class); binder.bind(ZkCoordinator.class).in(ManageLifecycle.class); binder.bind(ServerTypeConfig.class).toInstance(new ServerTypeConfig(ServerType.BROKER)); Jerseys.addResource(binder, HistoricalResource.class); From dcaf0d08686ea87f368cb535ded6e1daa7289da1 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Mon, 21 Apr 2025 13:16:37 +0530 Subject: [PATCH 24/38] Refactor --- docs/querying/query-context.md | 2 +- .../apache/druid/query/CloneQueryMode.java | 44 +++++++++++++++++-- .../client/selector/HistoricalFilter.java | 2 +- .../server/coordinator/ServerCloneStatus.java | 10 +++++ 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/docs/querying/query-context.md b/docs/querying/query-context.md index 61ddf0f96178..78aec8f9f286 100644 --- a/docs/querying/query-context.md +++ b/docs/querying/query-context.md @@ -66,7 +66,7 @@ See [SQL query context](sql-query-context.md) for other query context parameters |`debug`| `false` | Flag indicating whether to enable debugging outputs for the query. When set to false, no additional logs will be produced (logs produced will be entirely dependent on your logging level). When set to true, the following addition logs will be produced:
- Log the stack trace of the exception (if any) produced by the query | |`setProcessingThreadNames`|`true`| Whether processing thread names will be set to `queryType_dataSource_intervals` while processing a query. This aids in interpreting thread dumps, and is on by default. Query overhead can be reduced slightly by setting this to `false`. This has a tiny effect in most scenarios, but can be meaningful in high-QPS, low-per-segment-processing-time scenarios. | |`sqlPlannerBloat`|`1000`|Calcite parameter which controls whether to merge two Project operators when inlining expressions causes complexity to increase. Implemented as a workaround to exception `There are not enough rules to produce a node with desired properties: convention=DRUID, sort=[]` thrown after rejecting the merge of two projects.| -|`cloneQueryMode`|`EXCLUDE`| Indicates whether clone Historicals should be queried by brokers. Clone servers are created by the `cloneServers` Coordinator dynamic configuration. Possible values are `EXCLUDE`, `INCLUDE` and `CLONE_PREFERRED`. `EXCLUDE` means that clone Historicals are not queried by the broker. `CLONE_PREFERRED` indicates that when given a choice between the clone Historical and the original Historical which is being cloned, the broker chooses the clones; Historicals which are not involved in the cloning process will still be queried. `INCLUDE` means that broker queries any Historical without regarding clone status. This parameter only affects native queries; MSQ does not query Historicals directly, and Dart will not respect this context parameter.| +|`cloneQueryMode`|`excludeClones`| Indicates whether clone Historicals should be queried by brokers. Clone servers are created by the `cloneServers` Coordinator dynamic configuration. Possible values are `excludeClones`, `includeClones` and `clonesPreferred`. `excludeClones` means that clone Historicals are not queried by the broker. `clonesPreferred` indicates that when given a choice between the clone Historical and the original Historical which is being cloned, the broker chooses the clones; Historicals which are not involved in the cloning process will still be queried. `includeClones` means that broker queries any Historical without regarding clone status. This parameter only affects native queries; MSQ does not query Historicals directly, and Dart will not respect this context parameter.| ## Parameters by query type diff --git a/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java b/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java index bbcf831608b3..49259749679a 100644 --- a/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java +++ b/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java @@ -19,12 +19,50 @@ package org.apache.druid.query; +import com.fasterxml.jackson.annotation.JsonCreator; +import org.apache.druid.error.InvalidInput; + /** * Enum used in the query context to determine if clone queries should be used by native queries. */ public enum CloneQueryMode { - CLONE_PREFERRED, - INCLUDE, - EXCLUDE + /** + * For each ongoing cloning, do not query the source server that is being cloned. Other servers which are not + * participating in any cloning will still be queried. + */ + CLONES_PREFERRED("clonesPreferred"), + /** + * Consider both clones and their source servers for querying. + */ + INCLUDE("includeClones"), + /** + * Do not query clone servers. + */ + EXCLUDE("excludeClones"); + + private final String name; + + CloneQueryMode(String name) + { + this.name = name; + } + + @JsonCreator + public static CloneQueryMode fromString(String value) + { + for (CloneQueryMode mode : values()) { + if (mode.toString().equals(value)) { + return mode; + } + } + + throw InvalidInput.exception("No such clone query mode[%s]", value); + } + + @Override + public String toString() + { + return name; + } } diff --git a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java index ab64ac8f4cc9..8400a80f958d 100644 --- a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java +++ b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java @@ -44,7 +44,7 @@ public HistoricalFilter(BrokerViewOfCoordinatorConfig configView, CloneQueryMode { this.serversToFilter = () -> { switch (cloneQueryMode) { - case CLONE_PREFERRED: + case CLONES_PREFERRED: // Remove servers being cloned targets, so that clones are queried. return configView.getServersBeingCloned(); case EXCLUDE: diff --git a/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java b/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java index deb1ff43ad26..44113585bdd2 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java @@ -123,8 +123,18 @@ public String toString() */ public enum State { + /** + * The source server is missing from the current cluster view. The clone is continuing to load segments based on the + * last seen state of the source cluster. + */ SOURCE_SERVER_MISSING, + /** + * The target server is missing from the current cluster view. + */ TARGET_SERVER_MISSING, + /** + * Segments are loaded or being loaded. The counts give a better view of the progress. + */ LOADING } } From 3f692d3cc99e9f6357fefd87987828095d6f7339 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Mon, 21 Apr 2025 14:08:58 +0530 Subject: [PATCH 25/38] Refactor --- .../movingaverage/MovingAverageQueryTest.java | 7 ++- .../controller/DartTableInputSpecSlicer.java | 7 ++- .../client/BrokerViewOfCoordinatorConfig.java | 48 ++++++++++++++- .../druid/client/CachingClusteredClient.java | 22 ++++--- .../apache/druid/client/ServerViewUtil.java | 11 ++-- .../client/selector/HistoricalFilter.java | 59 ++----------------- .../druid/client/selector/ServerSelector.java | 19 +++--- .../druid/server/BrokerQueryResource.java | 5 +- .../druid/server/ClientInfoResource.java | 4 +- .../server/ClientQuerySegmentWalker.java | 2 + .../coordinator/CloneStatusManager.java | 41 +------------ .../coordinator/duty/CloneHistoricals.java | 49 ++++++++++++++- .../druid/client/BrokerServerViewTest.java | 17 +++--- ...ingClusteredClientCacheKeyManagerTest.java | 25 ++++---- .../CachingClusteredClientPerfTest.java | 4 +- .../client/CachingClusteredClientTest.java | 4 +- .../druid/client/DirectDruidClientTest.java | 3 +- ...ectionCountServerSelectorStrategyTest.java | 5 +- .../selector/TierSelectorStrategyTest.java | 9 +-- ...yRunnerBasedOnClusteredClientTestBase.java | 4 +- 20 files changed, 189 insertions(+), 156 deletions(-) diff --git a/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java b/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java index bbd99f897975..9ce71fbb8258 100644 --- a/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java +++ b/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java @@ -31,8 +31,8 @@ import com.google.inject.multibindings.Multibinder; import com.google.inject.name.Names; import com.google.inject.util.Providers; -import org.apache.druid.client.CachingClusteredClient; import org.apache.druid.client.BrokerViewOfCoordinatorConfig; +import org.apache.druid.client.CachingClusteredClient; import org.apache.druid.client.DruidServer; import org.apache.druid.client.ImmutableDruidServer; import org.apache.druid.client.TimelineServerView; @@ -318,7 +318,8 @@ public long getMaxQueuedBytes() return 0L; } }; - + BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig = new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()); + brokerViewOfCoordinatorConfig.start(); CachingClusteredClient baseClient = new CachingClusteredClient( conglomerate, new TimelineServerView() @@ -359,7 +360,7 @@ public void registerServerRemovedCallback(Executor exec, ServerRemovedCallback c } }, - new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()), + brokerViewOfCoordinatorConfig, MapCache.create(100000), jsonMapper, new ForegroundCachePopulator(jsonMapper, new CachePopulatorStats(), -1), diff --git a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java index 86ba4b80f892..82e07dc10228 100644 --- a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java +++ b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java @@ -40,6 +40,7 @@ import org.apache.druid.msq.input.table.RichSegmentDescriptor; import org.apache.druid.msq.input.table.SegmentsInputSlice; import org.apache.druid.msq.input.table.TableInputSpec; +import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.TableDataSource; import org.apache.druid.query.filter.DimFilterUtils; import org.apache.druid.server.coordination.DruidServerMetadata; @@ -163,7 +164,8 @@ public List sliceDynamic( */ int findWorkerForServerSelector(final ServerSelector serverSelector, final int maxNumSlices) { - final QueryableDruidServer server = serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER); + // Currently, Dart does not support clone query modes, all servers can be queried. + final QueryableDruidServer server = serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE); if (server == null) { return UNKNOWN; @@ -280,7 +282,8 @@ static boolean shouldIncludeSegment(final ServerSelector serverSelector) int numRealtimeServers = 0; int numOtherServers = 0; - for (final DruidServerMetadata server : serverSelector.getAllServers(HistoricalFilter.IDENTITY_FILTER)) { + // Currently, Dart does not support clone query modes, all servers can be queried. + for (final DruidServerMetadata server : serverSelector.getAllServers(HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.INCLUDE)) { if (SegmentSource.REALTIME.getUsedServerTypes().contains(server.getType())) { numRealtimeServers++; } else { diff --git a/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java index 05c8c71cf6c5..bbeaf7fc1aa5 100644 --- a/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java +++ b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java @@ -22,22 +22,26 @@ import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.concurrent.GuardedBy; import com.google.inject.Inject; +import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap; import org.apache.druid.client.coordinator.CoordinatorClient; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.java.util.common.lifecycle.LifecycleStart; import org.apache.druid.java.util.common.logger.Logger; +import org.apache.druid.query.CloneQueryMode; import org.apache.druid.server.DruidInternalDynamicConfigResource; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import javax.validation.constraints.NotNull; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /** * Broker view of the coordinator dynamic configuration, and its derived values such as target and source clone servers. * This class is registered as a managed lifecycle to fetch the coordinator dynamic configuration on startup. Further * updates are handled through {@link DruidInternalDynamicConfigResource}. */ -public class BrokerViewOfCoordinatorConfig +public class BrokerViewOfCoordinatorConfig implements HistoricalFilter { private static final Logger log = new Logger(BrokerViewOfCoordinatorConfig.class); private final CoordinatorClient coordinatorClient; @@ -99,4 +103,46 @@ public void start() throw new RuntimeException(e); } } + + @Override + public Int2ObjectRBTreeMap> getQueryableServers( + Int2ObjectRBTreeMap> historicalServers, + CloneQueryMode mode + ) + { + final Set serversToIgnore = getCurrentServersToIgnore(mode); + + if (serversToIgnore.isEmpty()) { + return historicalServers; + } + + final Int2ObjectRBTreeMap> filteredHistoricals = new Int2ObjectRBTreeMap<>(); + for (int priority : historicalServers.keySet()) { + Set servers = historicalServers.get(priority); + filteredHistoricals.put(priority, + servers.stream() + .filter(server -> !serversToIgnore.contains(server.getServer().getHost())) + .collect(Collectors.toSet()) + ); + } + + return filteredHistoricals; + } + + private Set getCurrentServersToIgnore(CloneQueryMode cloneQueryMode) + { + switch (cloneQueryMode) { + case CLONES_PREFERRED: + // Remove servers being cloned targets, so that clones are queried. + return getServersBeingCloned(); + case EXCLUDE: + // Remove clones, so that targets are queried. + return getClones(); + case INCLUDE: + // Don't remove either + return ImmutableSet.of(); + default: + throw new IllegalStateException("Unexpected value: " + cloneQueryMode); + } + } } diff --git a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java index 718716294efe..21c62674ee84 100644 --- a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java +++ b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java @@ -58,6 +58,7 @@ import org.apache.druid.query.BrokerParallelMergeConfig; import org.apache.druid.query.BySegmentResultValueClass; import org.apache.druid.query.CacheStrategy; +import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.Queries; import org.apache.druid.query.Query; import org.apache.druid.query.QueryContext; @@ -347,17 +348,14 @@ ClusterQueryResult run( } final Set segmentServers = computeSegmentsToQuery(timeline, specificSegments); - final HistoricalFilter historicalFilter = new HistoricalFilter( - brokerViewOfCoordinatorConfig, - query.context().getCloneQueryMode() - ); + final CloneQueryMode cloneQueryMode = query.context().getCloneQueryMode(); @Nullable final byte[] queryCacheKey = cacheKeyManager.computeSegmentLevelQueryCacheKey(); @Nullable final String prevEtag = (String) query.getContext().get(QueryResource.HEADER_IF_NONE_MATCH); if (prevEtag != null) { @Nullable - final String currentEtag = cacheKeyManager.computeResultLevelCachingEtag(segmentServers, historicalFilter, queryCacheKey); + final String currentEtag = cacheKeyManager.computeResultLevelCachingEtag(segmentServers, brokerViewOfCoordinatorConfig, cloneQueryMode, queryCacheKey); if (null != currentEtag) { responseContext.putEntityTag(currentEtag); } @@ -374,7 +372,11 @@ ClusterQueryResult run( queryPlus = queryPlus.withQueryMetrics(toolChest); queryPlus.getQueryMetrics().reportQueriedSegmentCount(segmentServers.size()).emit(emitter); - final SortedMap> segmentsByServer = groupSegmentsByServer(segmentServers, historicalFilter); + final SortedMap> segmentsByServer = groupSegmentsByServer( + segmentServers, + brokerViewOfCoordinatorConfig, + cloneQueryMode + ); LazySequence mergedResultSequence = new LazySequence<>(() -> { List> sequencesByInterval = new ArrayList<>(alreadyCachedResults.size() + segmentsByServer.size()); addSequencesFromCache(sequencesByInterval, alreadyCachedResults); @@ -604,13 +606,14 @@ private Cache.NamedKey getCachePopulatorKey(String segmentId, Interval segmentIn private SortedMap> groupSegmentsByServer( Set segments, - HistoricalFilter historicalFilter + HistoricalFilter historicalFilter, + CloneQueryMode cloneQueryMode ) { final SortedMap> serverSegments = new TreeMap<>(); for (SegmentServerSelector segmentServer : segments) { final QueryableDruidServer queryableDruidServer = segmentServer.getServer() - .pick(query, historicalFilter); + .pick(query, historicalFilter, cloneQueryMode); if (queryableDruidServer == null) { log.makeAlert( @@ -823,13 +826,14 @@ byte[] computeSegmentLevelQueryCacheKey() String computeResultLevelCachingEtag( final Set segments, final HistoricalFilter historicalFilter, + final CloneQueryMode cloneQueryMode, @Nullable byte[] queryCacheKey ) { Hasher hasher = Hashing.sha1().newHasher(); boolean hasOnlyHistoricalSegments = true; for (SegmentServerSelector p : segments) { - QueryableDruidServer queryableServer = p.getServer().pick(query, historicalFilter); + QueryableDruidServer queryableServer = p.getServer().pick(query, historicalFilter, cloneQueryMode); if (queryableServer == null || !queryableServer.getServer().isSegmentReplicationTarget()) { hasOnlyHistoricalSegments = false; break; diff --git a/server/src/main/java/org/apache/druid/client/ServerViewUtil.java b/server/src/main/java/org/apache/druid/client/ServerViewUtil.java index 4e8584ee06d3..3771be4cdfce 100644 --- a/server/src/main/java/org/apache/druid/client/ServerViewUtil.java +++ b/server/src/main/java/org/apache/druid/client/ServerViewUtil.java @@ -21,6 +21,7 @@ import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; +import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.LocatedSegmentDescriptor; import org.apache.druid.query.SegmentDescriptor; import org.apache.druid.query.TableDataSource; @@ -44,10 +45,11 @@ public static List getTargetLocations( String datasource, List intervals, int numCandidates, - HistoricalFilter historicalFilter + HistoricalFilter historicalFilter, + CloneQueryMode cloneQueryMode ) { - return getTargetLocations(serverView, new TableDataSource(datasource), intervals, numCandidates, historicalFilter); + return getTargetLocations(serverView, new TableDataSource(datasource), intervals, numCandidates, historicalFilter, cloneQueryMode); } public static List getTargetLocations( @@ -55,7 +57,8 @@ public static List getTargetLocations( TableDataSource datasource, List intervals, int numCandidates, - HistoricalFilter historicalFilter + HistoricalFilter historicalFilter, + CloneQueryMode cloneQueryMode ) { final Optional> maybeTimeline = serverView.getTimeline(datasource); @@ -71,7 +74,7 @@ public static List getTargetLocations( holder.getInterval(), holder.getVersion(), chunk.getChunkNumber() ); long size = selector.getSegment().getSize(); - List candidates = selector.getCandidates(numCandidates, historicalFilter); + List candidates = selector.getCandidates(numCandidates, historicalFilter, cloneQueryMode); located.add(new LocatedSegmentDescriptor(descriptor, size, candidates)); } } diff --git a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java index 8400a80f958d..2b0223a5c448 100644 --- a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java +++ b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java @@ -19,65 +19,18 @@ package org.apache.druid.client.selector; -import com.google.common.collect.ImmutableSet; import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap; -import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.QueryableDruidServer; import org.apache.druid.query.CloneQueryMode; import java.util.Set; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; -public class HistoricalFilter implements Function>, Int2ObjectRBTreeMap>> +public interface HistoricalFilter { - public static final HistoricalFilter IDENTITY_FILTER = new HistoricalFilter(ImmutableSet::of); - private final Supplier> serversToFilter; + public static final HistoricalFilter IDENTITY_FILTER = (historicalServers, mode) -> historicalServers; - public HistoricalFilter(Supplier> serversToFilter) - { - this.serversToFilter = serversToFilter; - } - - public HistoricalFilter(BrokerViewOfCoordinatorConfig configView, CloneQueryMode cloneQueryMode) - { - this.serversToFilter = () -> { - switch (cloneQueryMode) { - case CLONES_PREFERRED: - // Remove servers being cloned targets, so that clones are queried. - return configView.getServersBeingCloned(); - case EXCLUDE: - // Remove clones, so that targets are queried. - return configView.getClones(); - case INCLUDE: - // Don't remove either - return ImmutableSet.of(); - default: - throw new IllegalStateException("Unexpected value: " + cloneQueryMode); - } - }; - } - - @Override - public Int2ObjectRBTreeMap> apply(Int2ObjectRBTreeMap> historicalServers) - { - Set serversToIgnore = serversToFilter.get(); - - if (serversToIgnore.isEmpty()) { - return historicalServers; - } - - final Int2ObjectRBTreeMap> filteredHistoricals = new Int2ObjectRBTreeMap<>(); - for (int priority : historicalServers.keySet()) { - Set servers = historicalServers.get(priority); - filteredHistoricals.put(priority, - servers.stream() - .filter(server -> !serversToIgnore.contains(server.getServer().getHost())) - .collect(Collectors.toSet()) - ); - } - - return filteredHistoricals; - } + Int2ObjectRBTreeMap> getQueryableServers( + Int2ObjectRBTreeMap> historicalServers, + CloneQueryMode mode + ); } diff --git a/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java b/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java index 58e3162fe4dd..0586f5ebd5b8 100644 --- a/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java +++ b/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java @@ -23,6 +23,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap; import org.apache.druid.client.DataSegmentInterner; import org.apache.druid.client.QueryableDruidServer; +import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.Query; import org.apache.druid.server.coordination.DruidServerMetadata; import org.apache.druid.server.coordination.ServerType; @@ -121,13 +122,17 @@ public boolean isEmpty() } } - public List getCandidates(final int numCandidates, HistoricalFilter filter) + public List getCandidates( + final int numCandidates, + final HistoricalFilter filter, + final CloneQueryMode cloneQueryMode + ) { List candidates; synchronized (this) { if (numCandidates > 0) { candidates = new ArrayList<>(numCandidates); - strategy.pick(filter.apply(historicalServers), segment.get(), numCandidates) + strategy.pick(filter.getQueryableServers(historicalServers, cloneQueryMode), segment.get(), numCandidates) .stream() .map(server -> server.getServer().getMetadata()) .forEach(candidates::add); @@ -140,17 +145,17 @@ public List getCandidates(final int numCandidates, Historic } return candidates; } else { - return getAllServers(filter); + return getAllServers(filter, cloneQueryMode); } } } - public List getAllServers(HistoricalFilter filter) + public List getAllServers(HistoricalFilter filter, CloneQueryMode cloneQueryMode) { final List servers = new ArrayList<>(); synchronized (this) { - filter.apply(historicalServers) + filter.getQueryableServers(historicalServers, cloneQueryMode) .values() .stream() .flatMap(Collection::stream) @@ -168,11 +173,11 @@ public List getAllServers(HistoricalFilter filter) } @Nullable - public QueryableDruidServer pick(@Nullable Query query, HistoricalFilter filter) + public QueryableDruidServer pick(@Nullable Query query, HistoricalFilter filter, CloneQueryMode cloneQueryMode) { synchronized (this) { if (!historicalServers.isEmpty()) { - return strategy.pick(query, filter.apply(historicalServers), segment.get()); + return strategy.pick(query, filter.getQueryableServers(historicalServers, cloneQueryMode), segment.get()); } return strategy.pick(query, realtimeServers, segment.get()); } diff --git a/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java b/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java index e3b122aa489d..58fe86e0f919 100644 --- a/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java +++ b/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java @@ -26,7 +26,6 @@ import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.ServerViewUtil; import org.apache.druid.client.TimelineServerView; -import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.guice.annotations.Json; import org.apache.druid.guice.annotations.Self; import org.apache.druid.guice.annotations.Smile; @@ -111,14 +110,14 @@ public Response getQueryTargets( try { Query query = ioReaderWriter.getRequestMapper().readValue(in, Query.class); ExecutionVertex ev = ExecutionVertex.of(query); - HistoricalFilter historicalFilter = new HistoricalFilter(configView, cloneQueryMode); return ioReaderWriter.getResponseWriter().ok( ServerViewUtil.getTargetLocations( brokerServerView, ev.getBaseTableDataSource(), ev.getEffectiveQuerySegmentSpec().getIntervals(), numCandidates, - historicalFilter + configView, + cloneQueryMode ) ); } diff --git a/server/src/main/java/org/apache/druid/server/ClientInfoResource.java b/server/src/main/java/org/apache/druid/server/ClientInfoResource.java index 50099a21d1c4..09a8c81b78ac 100644 --- a/server/src/main/java/org/apache/druid/server/ClientInfoResource.java +++ b/server/src/main/java/org/apache/druid/server/ClientInfoResource.java @@ -30,7 +30,6 @@ import org.apache.druid.client.FilteredServerInventoryView; import org.apache.druid.client.ServerViewUtil; import org.apache.druid.client.TimelineServerView; -import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.java.util.common.DateTimes; import org.apache.druid.java.util.common.Intervals; @@ -323,8 +322,7 @@ public Iterable getQueryTargets( intervalList.add(Intervals.of(interval.trim())); } List condensed = JodaUtils.condenseIntervals(intervalList); - HistoricalFilter historicalFilter = new HistoricalFilter(configView, cloneQueryMode == null ? CloneQueryMode.EXCLUDE : cloneQueryMode); - return ServerViewUtil.getTargetLocations(timelineServerView, datasource, condensed, numCandidates, historicalFilter); + return ServerViewUtil.getTargetLocations(timelineServerView, datasource, condensed, numCandidates, configView, cloneQueryMode); } protected DateTime getCurrentTime() diff --git a/server/src/main/java/org/apache/druid/server/ClientQuerySegmentWalker.java b/server/src/main/java/org/apache/druid/server/ClientQuerySegmentWalker.java index 260e1c40319b..4d284f442c3e 100644 --- a/server/src/main/java/org/apache/druid/server/ClientQuerySegmentWalker.java +++ b/server/src/main/java/org/apache/druid/server/ClientQuerySegmentWalker.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.inject.Inject; @@ -607,6 +608,7 @@ private QueryRunner decorateClusterRunner(Query query, QueryRunner * @param parentQueryResourceId Parent Query's Query Resource ID * @return DataSource populated with the subqueries */ + @VisibleForTesting public static DataSource generateSubqueryIds( DataSource rootDataSource, @Nullable final String parentQueryId, diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java index c0583be46988..de4e78fbff5f 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java @@ -20,11 +20,8 @@ package org.apache.druid.server.coordinator; import com.google.common.collect.ImmutableMap; -import org.apache.druid.server.coordinator.loading.SegmentAction; -import org.apache.druid.timeline.DataSegment; import javax.annotation.Nullable; -import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; @@ -48,44 +45,8 @@ public ServerCloneStatus getStatusForServer(String targetServer) return cloneStatusSnapshot.get().get(targetServer); } - public void updateStatus(Map historicalMap, Map cloneServers) + public void updateStatus(Map newStatusMap) { - final Map newStatusMap = new HashMap<>(); - - for (Map.Entry entry : cloneServers.entrySet()) { - final String targetServerName = entry.getKey(); - final ServerHolder targetServer = historicalMap.get(entry.getKey()); - final String sourceServerName = entry.getValue(); - - long segmentLoad = 0L; - long bytesLeft = 0L; - long segmentDrop = 0L; - - ServerCloneStatus newStatus; - if (targetServer == null) { - newStatus = ServerCloneStatus.unknown(sourceServerName); - } else { - - ServerCloneStatus.State state; - if (!historicalMap.containsKey(sourceServerName)) { - state = ServerCloneStatus.State.SOURCE_SERVER_MISSING; - } else { - state = ServerCloneStatus.State.LOADING; - } - - for (Map.Entry queuedSegment : targetServer.getQueuedSegments().entrySet()) { - if (queuedSegment.getValue().isLoad()) { - segmentLoad += 1; - bytesLeft += queuedSegment.getKey().getSize(); - } else { - segmentDrop += 1; - } - } - newStatus = new ServerCloneStatus(sourceServerName, state, segmentLoad, segmentDrop, bytesLeft); - } - newStatusMap.put(targetServerName, newStatus); - } - cloneStatusSnapshot.set(ImmutableMap.copyOf(newStatusMap)); } } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java b/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java index 9b1311084058..ef1daa8fac2c 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java @@ -24,6 +24,7 @@ import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import org.apache.druid.server.coordinator.DruidCluster; import org.apache.druid.server.coordinator.DruidCoordinatorRuntimeParams; +import org.apache.druid.server.coordinator.ServerCloneStatus; import org.apache.druid.server.coordinator.ServerHolder; import org.apache.druid.server.coordinator.loading.SegmentAction; import org.apache.druid.server.coordinator.loading.SegmentLoadQueueManager; @@ -34,6 +35,7 @@ import org.apache.druid.timeline.DataSegment; import java.util.Collection; +import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -121,8 +123,53 @@ public DruidCoordinatorRuntimeParams run(DruidCoordinatorRuntimeParams params) } } - cloneStatusManager.updateStatus(hostToHistorical, cloneServers); + Map newStatusMap = createCurrentStatusMap(hostToHistorical, cloneServers); + cloneStatusManager.updateStatus(newStatusMap); return params; } + + public Map createCurrentStatusMap( + Map historicalMap, + Map cloneServers + ) + { + final Map newStatusMap = new HashMap<>(); + + for (Map.Entry entry : cloneServers.entrySet()) { + final String targetServerName = entry.getKey(); + final ServerHolder targetServer = historicalMap.get(entry.getKey()); + final String sourceServerName = entry.getValue(); + + long segmentLoad = 0L; + long bytesLeft = 0L; + long segmentDrop = 0L; + + ServerCloneStatus newStatus; + if (targetServer == null) { + newStatus = ServerCloneStatus.unknown(sourceServerName); + } else { + + ServerCloneStatus.State state; + if (!historicalMap.containsKey(sourceServerName)) { + state = ServerCloneStatus.State.SOURCE_SERVER_MISSING; + } else { + state = ServerCloneStatus.State.LOADING; + } + + for (Map.Entry queuedSegment : targetServer.getQueuedSegments().entrySet()) { + if (queuedSegment.getValue().isLoad()) { + segmentLoad += 1; + bytesLeft += queuedSegment.getKey().getSize(); + } else { + segmentDrop += 1; + } + } + newStatus = new ServerCloneStatus(sourceServerName, state, segmentLoad, segmentDrop, bytesLeft); + } + newStatusMap.put(targetServerName, newStatus); + } + + return newStatusMap; + } } diff --git a/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java b/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java index 973feb478bc6..67fbd3823073 100644 --- a/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java +++ b/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java @@ -39,6 +39,7 @@ import org.apache.druid.java.util.common.Intervals; import org.apache.druid.java.util.common.Pair; import org.apache.druid.java.util.http.client.HttpClient; +import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.QueryRunnerFactoryConglomerate; import org.apache.druid.query.QueryWatcher; import org.apache.druid.query.TableDataSource; @@ -129,7 +130,7 @@ public void testSingleServerAddedRemovedSegment() throws Exception ServerSelector selector = (actualPartitionHolder.iterator().next()).getObject(); Assert.assertFalse(selector.isEmpty()); Assert.assertEquals(segment, selector.getSegment()); - Assert.assertEquals(druidServer, selector.pick(null, HistoricalFilter.IDENTITY_FILTER).getServer()); + Assert.assertEquals(druidServer, selector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE).getServer()); Assert.assertNotNull(timeline.findChunk(intervals, "v1", partition)); unannounceSegmentForServer(druidServer, segment, zkPathsConfig); @@ -388,9 +389,9 @@ public void testMultipleTiers() throws Exception // Verify that the ServerSelector always picks Tier 1 for (int i = 0; i < 5; ++i) { - Assert.assertEquals(server21, selector.pick(null, HistoricalFilter.IDENTITY_FILTER).getServer()); + Assert.assertEquals(server21, selector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE).getServer()); } - Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER)); + Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); } @Test @@ -448,9 +449,9 @@ public void testRealtimeTasksNotWatched() throws Exception // Verify that the ServerSelector always picks the Historical server for (int i = 0; i < 5; ++i) { - Assert.assertEquals(historicalServer, selector.pick(null, HistoricalFilter.IDENTITY_FILTER).getServer()); + Assert.assertEquals(historicalServer, selector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE).getServer()); } - Assert.assertEquals(Collections.singletonList(historicalServer.getMetadata()), selector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER)); + Assert.assertEquals(Collections.singletonList(historicalServer.getMetadata()), selector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); } @Test @@ -510,9 +511,9 @@ public void testIgnoredTiers() throws Exception // Verify that the ServerSelector always picks Tier 1 for (int i = 0; i < 5; ++i) { - Assert.assertEquals(server21, selector.pick(null, HistoricalFilter.IDENTITY_FILTER).getServer()); + Assert.assertEquals(server21, selector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE).getServer()); } - Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER)); + Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); } @Test(expected = ISE.class) @@ -592,7 +593,7 @@ private void assertValues( ServerSelector selector = ((SingleElementPartitionChunk) actualPartitionHolder.iterator() .next()).getObject(); Assert.assertFalse(selector.isEmpty()); - Assert.assertEquals(expectedPair.rhs.rhs.lhs, selector.pick(null, HistoricalFilter.IDENTITY_FILTER).getServer()); + Assert.assertEquals(expectedPair.rhs.rhs.lhs, selector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE).getServer()); Assert.assertEquals(expectedPair.rhs.rhs.rhs, selector.getSegment()); } } diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java index d3ef6960b382..e3dfcb7cbfa3 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java @@ -25,6 +25,7 @@ import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.query.CacheStrategy; +import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.DataSource; import org.apache.druid.query.Query; import org.apache.druid.query.QueryContext; @@ -87,7 +88,7 @@ public void testComputeEtag_nonHistorical() makeHistoricalServerSelector(0), makeRealtimeServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, QUERY_CACHE_KEY); + String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); Assert.assertNull(actual); } @@ -100,14 +101,14 @@ public void testComputeEtag_DifferentHistoricals() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, QUERY_CACHE_KEY); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); Assert.assertNotNull(actual1); selectors = ImmutableSet.of( makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, QUERY_CACHE_KEY); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); Assert.assertNotNull(actual2); Assert.assertEquals("cache key should not change for same server selectors", actual1, actual2); @@ -115,7 +116,7 @@ public void testComputeEtag_DifferentHistoricals() makeHistoricalServerSelector(2), makeHistoricalServerSelector(1) ); - String actual3 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, QUERY_CACHE_KEY); + String actual3 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); Assert.assertNotNull(actual3); Assert.assertNotEquals(actual1, actual3); } @@ -129,10 +130,10 @@ public void testComputeEtag_DifferentQueryCacheKey() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, new byte[]{1, 2}); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, new byte[]{1, 2}); Assert.assertNotNull(actual1); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, new byte[]{3, 4}); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, new byte[]{3, 4}); Assert.assertNotNull(actual2); Assert.assertNotEquals(actual1, actual2); } @@ -147,14 +148,14 @@ public void testComputeEtag_nonJoinDataSource() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, FULL_QUERY_CACHE_KEY); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, FULL_QUERY_CACHE_KEY); Assert.assertNotNull(actual1); selectors = ImmutableSet.of( makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, null); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, null); Assert.assertNotNull(actual2); Assert.assertEquals(actual1, actual2); } @@ -170,7 +171,7 @@ public void testComputeEtag_joinWithUnsupportedCaching() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, null); Assert.assertNull(actual); } @@ -188,7 +189,7 @@ public void testComputeEtag_noEffectifBySegment() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, null); Assert.assertNotNull(actual); } @@ -207,7 +208,7 @@ public void testComputeEtag_noEffectIfUseAndPopulateFalse() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, null); Assert.assertNotNull(actual); } @@ -304,7 +305,7 @@ private SegmentServerSelector makeServerSelector(boolean isHistorical, int parti 0 ); expect(server.isSegmentReplicationTarget()).andReturn(isHistorical).anyTimes(); - expect(serverSelector.pick(query, HistoricalFilter.IDENTITY_FILTER)).andReturn(queryableDruidServer).anyTimes(); + expect(serverSelector.pick(query, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)).andReturn(queryableDruidServer).anyTimes(); expect(queryableDruidServer.getServer()).andReturn(server).anyTimes(); expect(serverSelector.getSegment()).andReturn(segment).anyTimes(); replay(serverSelector, queryableDruidServer, server); diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java index c7509a2168ab..bde66a7425cf 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java @@ -129,10 +129,12 @@ public void testGetQueryRunnerForSegments_singleIntervalLargeSegments() Mockito.doReturn(Optional.of(timeline)).when(serverView).getTimeline(any()); Mockito.doReturn(new MockQueryRunner()).when(serverView).getQueryRunner(any()); + BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig = new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()); + brokerViewOfCoordinatorConfig.start(); CachingClusteredClient cachingClusteredClient = new CachingClusteredClient( new MockQueryRunnerFactoryConglomerate(), serverView, - new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()), + brokerViewOfCoordinatorConfig, MapCache.create(1024), TestHelper.makeJsonMapper(), Mockito.mock(CachePopulator.class), diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java index 52f9414d63f9..a3b1edaededf 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java @@ -2605,6 +2605,8 @@ protected CachingClusteredClient makeClient( final int mergeLimit ) { + BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig = new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()); + brokerViewOfCoordinatorConfig.start(); return new CachingClusteredClient( conglomerateRule.getConglomerate(), new TimelineServerView() @@ -2644,7 +2646,7 @@ public void registerServerRemovedCallback(Executor exec, ServerRemovedCallback c } }, - new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()), + brokerViewOfCoordinatorConfig, cache, JSON_MAPPER, cachePopulator, diff --git a/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java b/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java index e9598efaafb1..e8abaf120852 100644 --- a/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java +++ b/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java @@ -39,6 +39,7 @@ import org.apache.druid.java.util.http.client.Request; import org.apache.druid.java.util.http.client.response.HttpResponseHandler; import org.apache.druid.java.util.http.client.response.StatusResponseHolder; +import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.Druids; import org.apache.druid.query.Query; import org.apache.druid.query.QueryInterruptedException; @@ -244,7 +245,7 @@ public void testRun() throws Exception Assert.assertEquals(2, client2.getNumOpenConnections()); - Assert.assertEquals(serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER), queryableDruidServer2); + Assert.assertEquals(serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE), queryableDruidServer2); EasyMock.verify(httpClient); } diff --git a/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java b/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java index 0ad96a81cfd5..4ac309f5a762 100644 --- a/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java +++ b/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java @@ -24,6 +24,7 @@ import org.apache.druid.client.QueryableDruidServer; import org.apache.druid.java.util.common.DateTimes; import org.apache.druid.java.util.common.Intervals; +import org.apache.druid.query.CloneQueryMode; import org.apache.druid.server.coordination.ServerType; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.partition.NumberedShardSpec; @@ -50,7 +51,7 @@ public void testDifferentConnectionCount() ServerSelector serverSelector = initSelector(s1, s2, s3); for (int i = 0; i < 100; ++i) { - Assert.assertEquals(s2, serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER)); + Assert.assertEquals(s2, serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); } } @@ -63,7 +64,7 @@ public void testBalancerTieBreaking() Set pickedServers = new HashSet<>(); for (int i = 0; i < 100; ++i) { - pickedServers.add(serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER).getServer().getName()); + pickedServers.add(serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE).getServer().getName()); } Assert.assertTrue( "Multiple servers should be selected when the number of connections is equal.", diff --git a/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java b/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java index 58e88a27eaa3..f84914dd893d 100644 --- a/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java +++ b/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java @@ -24,6 +24,7 @@ import org.apache.druid.client.QueryableDruidServer; import org.apache.druid.java.util.common.DateTimes; import org.apache.druid.java.util.common.Intervals; +import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.Query; import org.apache.druid.server.coordination.DruidServerMetadata; import org.apache.druid.server.coordination.ServerType; @@ -240,10 +241,10 @@ private void testTierSelectorStrategy( serverSelector.addServerAndUpdateSegment(server, serverSelector.getSegment()); } - Assert.assertEquals(expectedSelection[0], serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER)); - Assert.assertEquals(expectedSelection[0], serverSelector.pick(EasyMock.createMock(Query.class), HistoricalFilter.IDENTITY_FILTER)); - Assert.assertEquals(expectedCandidates, serverSelector.getCandidates(-1, HistoricalFilter.IDENTITY_FILTER)); - Assert.assertEquals(expectedCandidates.subList(0, 2), serverSelector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER)); + Assert.assertEquals(expectedSelection[0], serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(expectedSelection[0], serverSelector.pick(EasyMock.createMock(Query.class), HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(expectedCandidates, serverSelector.getCandidates(-1, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(expectedCandidates.subList(0, 2), serverSelector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); } @Test diff --git a/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java b/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java index 1e62b29976e0..54e5eb6b7af7 100644 --- a/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java +++ b/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java @@ -123,10 +123,12 @@ public void setupTestBase() segmentGenerator = new SegmentGenerator(); httpClient = new TestHttpClient(objectMapper); simpleServerView = new SimpleServerView(conglomerate, objectMapper, httpClient); + BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig = new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()); + brokerViewOfCoordinatorConfig.start(); cachingClusteredClient = new CachingClusteredClient( conglomerate, simpleServerView, - new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()), + brokerViewOfCoordinatorConfig, MapCache.create(0), objectMapper, new ForegroundCachePopulator(objectMapper, new CachePopulatorStats(), 0), From 77aec3fb8d8537d0e55082f5402a71e250dec0e6 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Mon, 21 Apr 2025 17:05:45 +0530 Subject: [PATCH 26/38] Delete duty, move syncing to leadership start --- .../CachingClusteredClientBenchmark.java | 2 +- .../client/BrokerViewOfCoordinatorConfig.java | 16 +--- .../druid/client/broker/BrokerClient.java | 6 ++ .../druid/client/broker/BrokerClientImpl.java | 18 +++++ .../client/selector/HistoricalFilter.java | 2 +- .../server/coordinator/DruidCoordinator.java | 4 +- .../duty/SendDynamicConfigToBrokers.java | 43 ----------- .../http/CoordinatorDynamicConfigSyncer.java | 75 +++++++++++-------- .../CoordinatorDynamicConfigsResource.java | 2 +- .../BrokerViewOfCoordinatorConfigTest.java | 14 ---- 10 files changed, 76 insertions(+), 106 deletions(-) delete mode 100644 server/src/main/java/org/apache/druid/server/coordinator/duty/SendDynamicConfigToBrokers.java diff --git a/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java b/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java index 6085771a4b07..66e19282d66c 100644 --- a/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java +++ b/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java @@ -27,8 +27,8 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.google.common.collect.Ordering; -import org.apache.druid.client.CachingClusteredClient; import org.apache.druid.client.BrokerViewOfCoordinatorConfig; +import org.apache.druid.client.CachingClusteredClient; import org.apache.druid.client.DruidServer; import org.apache.druid.client.ImmutableDruidServer; import org.apache.druid.client.QueryableDruidServer; diff --git a/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java index bbeaf7fc1aa5..20b1cd3f6caa 100644 --- a/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java +++ b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java @@ -76,16 +76,6 @@ public synchronized void setDynamicConfig(@NotNull CoordinatorDynamicConfig upda this.serversBeingCloned = ImmutableSet.copyOf(cloneServers.values()); } - public synchronized Set getClones() - { - return cloneServers; - } - - public synchronized Set getServersBeingCloned() - { - return serversBeingCloned; - } - @LifecycleStart public void start() { @@ -129,15 +119,15 @@ public Int2ObjectRBTreeMap> getQueryableServers( return filteredHistoricals; } - private Set getCurrentServersToIgnore(CloneQueryMode cloneQueryMode) + private synchronized Set getCurrentServersToIgnore(CloneQueryMode cloneQueryMode) { switch (cloneQueryMode) { case CLONES_PREFERRED: // Remove servers being cloned targets, so that clones are queried. - return getServersBeingCloned(); + return serversBeingCloned; case EXCLUDE: // Remove clones, so that targets are queried. - return getClones(); + return cloneServers; case INCLUDE: // Don't remove either return ImmutableSet.of(); diff --git a/server/src/main/java/org/apache/druid/client/broker/BrokerClient.java b/server/src/main/java/org/apache/druid/client/broker/BrokerClient.java index ea370572c447..9cb519143d87 100644 --- a/server/src/main/java/org/apache/druid/client/broker/BrokerClient.java +++ b/server/src/main/java/org/apache/druid/client/broker/BrokerClient.java @@ -23,6 +23,7 @@ import org.apache.druid.query.explain.ExplainPlan; import org.apache.druid.query.http.ClientSqlQuery; import org.apache.druid.query.http.SqlTaskStatus; +import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import java.util.List; @@ -53,4 +54,9 @@ public interface BrokerClient * @param sqlQuery the SQL query for which the {@code EXPLAIN PLAN FOR} information is to be fetched */ ListenableFuture> fetchExplainPlan(ClientSqlQuery sqlQuery); + + /** + * Updates the broker with the given {@link CoordinatorDynamicConfig}. + */ + ListenableFuture updateDynamicConfig(CoordinatorDynamicConfig config); } diff --git a/server/src/main/java/org/apache/druid/client/broker/BrokerClientImpl.java b/server/src/main/java/org/apache/druid/client/broker/BrokerClientImpl.java index 5ad609147429..0217e86144be 100644 --- a/server/src/main/java/org/apache/druid/client/broker/BrokerClientImpl.java +++ b/server/src/main/java/org/apache/druid/client/broker/BrokerClientImpl.java @@ -33,7 +33,9 @@ import org.apache.druid.query.http.SqlTaskStatus; import org.apache.druid.rpc.RequestBuilder; import org.apache.druid.rpc.ServiceClient; +import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import org.jboss.netty.handler.codec.http.HttpMethod; +import org.jboss.netty.handler.codec.http.HttpResponseStatus; import java.nio.charset.StandardCharsets; import java.util.List; @@ -96,5 +98,21 @@ public ListenableFuture> fetchExplainPlan(final ClientSqlQuery holder -> JacksonUtils.readValue(jsonMapper, holder.getContent(), new TypeReference<>() {}) ); } + + @Override + public ListenableFuture updateDynamicConfig(CoordinatorDynamicConfig config) + { + final RequestBuilder requestBuilder = + new RequestBuilder(HttpMethod.POST, "/druid-internal/v1/config/coordinator") + .jsonContent(jsonMapper, config); + + return FutureUtils.transform( + client.asyncRequest(requestBuilder, new BytesFullResponseHandler()), + holder -> { + final HttpResponseStatus status = holder.getStatus(); + return status.equals(HttpResponseStatus.OK); + } + ); + } } diff --git a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java index 2b0223a5c448..f41c8c80e89e 100644 --- a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java +++ b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java @@ -27,7 +27,7 @@ public interface HistoricalFilter { - public static final HistoricalFilter IDENTITY_FILTER = (historicalServers, mode) -> historicalServers; + HistoricalFilter IDENTITY_FILTER = (historicalServers, mode) -> historicalServers; Int2ObjectRBTreeMap> getQueryableServers( Int2ObjectRBTreeMap> historicalServers, diff --git a/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java b/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java index c79ae92eb055..0a6ac7414459 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java @@ -83,7 +83,6 @@ import org.apache.druid.server.coordinator.duty.MetadataAction; import org.apache.druid.server.coordinator.duty.PrepareBalancerAndLoadQueues; import org.apache.druid.server.coordinator.duty.RunRules; -import org.apache.druid.server.coordinator.duty.SendDynamicConfigToBrokers; import org.apache.druid.server.coordinator.duty.UnloadUnusedSegments; import org.apache.druid.server.coordinator.loading.LoadQueuePeon; import org.apache.druid.server.coordinator.loading.LoadQueueTaskMaster; @@ -451,6 +450,7 @@ private void becomeLeader() if (coordinatorSegmentMetadataCache != null) { coordinatorSegmentMetadataCache.onLeaderStart(); } + coordinatorDynamicConfigSyncer.onLeaderStart(); final int startingLeaderCounter = coordLeaderSelector.localTerm(); dutiesRunnables.add( @@ -532,6 +532,7 @@ private void stopBeingLeader() } compactionStatusTracker.stop(); taskMaster.onLeaderStop(); + coordinatorDynamicConfigSyncer.onLeaderStop(); serviceAnnouncer.unannounce(self); lookupCoordinatorManager.stop(); metadataManager.onLeaderStop(); @@ -568,7 +569,6 @@ private List makeHistoricalManagementDuties() new MarkEternityTombstonesAsUnused(deleteSegments), new BalanceSegments(config.getCoordinatorPeriod()), new CloneHistoricals(loadQueueManager, cloneStatusManager), - new SendDynamicConfigToBrokers(coordinatorDynamicConfigSyncer), new CollectLoadQueueStats() ); } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/duty/SendDynamicConfigToBrokers.java b/server/src/main/java/org/apache/druid/server/coordinator/duty/SendDynamicConfigToBrokers.java deleted file mode 100644 index cd2cf944208c..000000000000 --- a/server/src/main/java/org/apache/druid/server/coordinator/duty/SendDynamicConfigToBrokers.java +++ /dev/null @@ -1,43 +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.server.coordinator.duty; - -import org.apache.druid.server.coordinator.DruidCoordinatorRuntimeParams; -import org.apache.druid.server.http.CoordinatorDynamicConfigSyncer; - -/** - * Duty to periodically broadcast the coordinator dynamic configuration to all brokers. - */ -public class SendDynamicConfigToBrokers implements CoordinatorDuty -{ - private final CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer; - - public SendDynamicConfigToBrokers(CoordinatorDynamicConfigSyncer coordinatorDynamicConfigSyncer) - { - this.coordinatorDynamicConfigSyncer = coordinatorDynamicConfigSyncer; - } - - @Override - public DruidCoordinatorRuntimeParams run(DruidCoordinatorRuntimeParams params) - { - coordinatorDynamicConfigSyncer.broadcastConfigToBrokers(); - return params; - } -} diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java index 9b8c5088ecc0..700c9e3de65b 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java @@ -21,6 +21,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.inject.Inject; +import org.apache.druid.client.broker.BrokerClient; +import org.apache.druid.client.broker.BrokerClientImpl; import org.apache.druid.discovery.DiscoveryDruidNode; import org.apache.druid.discovery.DruidNodeDiscoveryProvider; import org.apache.druid.discovery.NodeRole; @@ -29,25 +31,21 @@ import org.apache.druid.java.util.common.StringUtils; import org.apache.druid.java.util.common.concurrent.Execs; import org.apache.druid.java.util.common.logger.Logger; -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.FixedServiceLocator; -import org.apache.druid.rpc.RequestBuilder; -import org.apache.druid.rpc.ServiceClient; import org.apache.druid.rpc.ServiceClientFactory; import org.apache.druid.rpc.ServiceLocation; import org.apache.druid.rpc.StandardRetryPolicy; import org.apache.druid.server.DruidNode; import org.apache.druid.server.coordinator.CoordinatorConfigManager; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; -import org.jboss.netty.handler.codec.http.HttpMethod; -import org.jboss.netty.handler.codec.http.HttpResponseStatus; import javax.annotation.Nullable; import java.net.URL; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @@ -64,8 +62,9 @@ public class CoordinatorDynamicConfigSyncer private final AtomicReference lastKnownConfig = new AtomicReference<>(); private final ServiceClientFactory clientFactory; - private final ExecutorService exec; private final Set inSyncBrokers; + private final ScheduledExecutorService exec; + private @Nullable Future syncFuture = null; @Inject public CoordinatorDynamicConfigSyncer( @@ -79,18 +78,21 @@ public CoordinatorDynamicConfigSyncer( this.configManager = configManager; this.jsonMapper = jsonMapper; this.druidNodeDiscovery = druidNodeDiscoveryProvider; - this.exec = Execs.singleThreaded("DynamicConfigSyncer-%d"); + this.exec = Execs.scheduledSingleThreaded("CoordinatorDynamicConfigSyncer-%d"); this.inSyncBrokers = ConcurrentHashMap.newKeySet(); } + public void triggerBroadcastConfigToBrokers() + { + exec.submit(this::broadcastConfigToBrokers); + } + public void broadcastConfigToBrokers() { invalidateInSyncBrokersIfNeeded(); - exec.submit(() -> { - for (ServiceLocation broker : getKnownBrokers()) { - pushConfigToBroker(broker); - } - }); + for (ServiceLocation broker : getKnownBrokers()) { + pushConfigToBroker(broker); + } } public synchronized Set getInSyncBrokers() @@ -98,30 +100,41 @@ public synchronized Set getInSyncBrokers() return Set.copyOf(inSyncBrokers); } + public void onLeaderStart() + { + log.info("Starting coordinator config syncing to brokers on leader node."); + syncFuture = exec.scheduleAtFixedRate( + this::broadcastConfigToBrokers, + 1L, + 1L, + TimeUnit.MINUTES + ); + } + + public void onLeaderStop() + { + log.info("Not leader, stopping coordinator config syncing to brokers."); + if (syncFuture != null) { + syncFuture.cancel(true); + } + } + private void pushConfigToBroker(ServiceLocation brokerLocation) { - final ServiceClient brokerClient = clientFactory.makeClient( - NodeRole.BROKER.getJsonName(), - new FixedServiceLocator(brokerLocation), - StandardRetryPolicy.builder().maxAttempts(6).build() + final BrokerClient brokerClient = new BrokerClientImpl( + clientFactory.makeClient( + NodeRole.BROKER.getJsonName(), + new FixedServiceLocator(brokerLocation), + StandardRetryPolicy.builder().maxAttempts(6).build() + ), + jsonMapper ); try { CoordinatorDynamicConfig currentDynamicConfig = configManager.getCurrentDynamicConfig(); - final RequestBuilder requestBuilder = - new RequestBuilder(HttpMethod.POST, "/druid-internal/v1/config/coordinator") - .jsonContent(jsonMapper, currentDynamicConfig); - - final BytesFullResponseHolder responseHolder = brokerClient.request(requestBuilder, new BytesFullResponseHandler()); - final HttpResponseStatus status = responseHolder.getStatus(); - if (status.equals(HttpResponseStatus.OK)) { + boolean success = brokerClient.updateDynamicConfig(currentDynamicConfig).get(); + if (success) { markBrokerAsSynced(currentDynamicConfig, brokerLocation); - } else { - log.error( - "Received status [%s] while posting dynamic configs to broker[%s]", - status.getCode(), - brokerLocation - ); } } catch (Exception e) { diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java index f0738343da7b..a0a7027fbed9 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java @@ -95,7 +95,7 @@ public Response setDynamicConfigs( ); if (setResult.isOk()) { - coordinatorDynamicConfigSyncer.broadcastConfigToBrokers(); + coordinatorDynamicConfigSyncer.triggerBroadcastConfigToBrokers(); return Response.ok().build(); } else { return Response.status(Response.Status.BAD_REQUEST) diff --git a/server/src/test/java/org/apache/druid/client/BrokerViewOfCoordinatorConfigTest.java b/server/src/test/java/org/apache/druid/client/BrokerViewOfCoordinatorConfigTest.java index 907a3745ea3b..e8dfadb7261f 100644 --- a/server/src/test/java/org/apache/druid/client/BrokerViewOfCoordinatorConfigTest.java +++ b/server/src/test/java/org/apache/druid/client/BrokerViewOfCoordinatorConfigTest.java @@ -28,7 +28,6 @@ import org.mockito.Mockito; import java.util.Map; -import java.util.Set; public class BrokerViewOfCoordinatorConfigTest { @@ -56,17 +55,4 @@ public void testFetchesConfigOnStartup() Mockito.verify(coordinatorClient, Mockito.times(1)).getCoordinatorDynamicConfig(); Assert.assertEquals(config, target.getDynamicConfiguration()); } - - @Test - public void testCreatesServerLists() - { - config = CoordinatorDynamicConfig.builder() - .withCloneServers(Map.of("host1", "host2", "host4", "host5")) - .build(); - - target.setDynamicConfig(config); - - Assert.assertEquals(Set.of("host1", "host4"), target.getClones()); - Assert.assertEquals(Set.of("host2", "host5"), target.getServersBeingCloned()); - } } From 6b0f14130758a941b421df66d779c5568a6d0744 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Mon, 21 Apr 2025 21:59:47 +0530 Subject: [PATCH 27/38] Update APIs --- .../DruidInternalDynamicConfigResource.java | 2 +- .../druid/server/http/BrokerSyncStatus.java | 89 +++++++++++++++++++ .../http/CoordinatorDynamicConfigSyncer.java | 15 ++-- ...CoordinatorDynamicConfigsResourceTest.java | 4 +- 4 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java diff --git a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java index a62695e56d04..d9e9573715a0 100644 --- a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java +++ b/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java @@ -60,6 +60,6 @@ public Response getDynamicConfig() public Response setDynamicConfig(final CoordinatorDynamicConfig dynamicConfig) { brokerViewOfCoordinatorConfig.setDynamicConfig(dynamicConfig); - return Response.ok("OK").build(); + return Response.ok().build(); } } diff --git a/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java b/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java new file mode 100644 index 000000000000..a6d29d1119cb --- /dev/null +++ b/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java @@ -0,0 +1,89 @@ +/* + * 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.server.http; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.druid.rpc.ServiceLocation; + +import java.util.Objects; + +public class BrokerSyncStatus +{ + private final String host; + private final int port; + private final long syncTime; + + @JsonCreator + public BrokerSyncStatus( + @JsonProperty("host") String host, + @JsonProperty("port") int port, + @JsonProperty("syncTime") long syncTime + ) + { + this.host = host; + this.port = port; + this.syncTime = syncTime; + } + + public BrokerSyncStatus(ServiceLocation broker, long syncTime) + { + this.host = broker.getHost(); + this.port = broker.getTlsPort() > 0 ? broker.getTlsPort() : broker.getPlaintextPort(); + this.syncTime = syncTime; + } + + @JsonProperty + public String getHost() + { + return host; + } + + @JsonProperty + public int getPort() + { + return port; + } + + @JsonProperty + public long getSyncTime() + { + return syncTime; + } + + @Override + public boolean equals(Object o) + { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + BrokerSyncStatus that = (BrokerSyncStatus) o; + return port == that.port && Objects.equals(host, that.host); + } + + @Override + public int hashCode() + { + return Objects.hash(host, port); + } +} diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java index 700c9e3de65b..f10b3124d35b 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java @@ -28,7 +28,6 @@ import org.apache.druid.discovery.NodeRole; import org.apache.druid.guice.annotations.EscalatedGlobal; import org.apache.druid.guice.annotations.Json; -import org.apache.druid.java.util.common.StringUtils; import org.apache.druid.java.util.common.concurrent.Execs; import org.apache.druid.java.util.common.logger.Logger; import org.apache.druid.rpc.FixedServiceLocator; @@ -40,7 +39,6 @@ import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import javax.annotation.Nullable; -import java.net.URL; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; @@ -62,7 +60,7 @@ public class CoordinatorDynamicConfigSyncer private final AtomicReference lastKnownConfig = new AtomicReference<>(); private final ServiceClientFactory clientFactory; - private final Set inSyncBrokers; + private final Set inSyncBrokers; private final ScheduledExecutorService exec; private @Nullable Future syncFuture = null; @@ -95,7 +93,7 @@ public void broadcastConfigToBrokers() } } - public synchronized Set getInSyncBrokers() + public synchronized Set getInSyncBrokers() { return Set.copyOf(inSyncBrokers); } @@ -105,9 +103,9 @@ public void onLeaderStart() log.info("Starting coordinator config syncing to brokers on leader node."); syncFuture = exec.scheduleAtFixedRate( this::broadcastConfigToBrokers, - 1L, - 1L, - TimeUnit.MINUTES + 30L, + 60L, + TimeUnit.SECONDS ); } @@ -168,9 +166,8 @@ private synchronized void invalidateInSyncBrokersIfNeeded() private synchronized void markBrokerAsSynced(CoordinatorDynamicConfig config, ServiceLocation broker) { - final URL url = broker.toURL(""); if (config.equals(lastKnownConfig.get())) { - inSyncBrokers.add(StringUtils.format("%s:%s", url.getHost(), url.getPort())); + inSyncBrokers.add(new BrokerSyncStatus(broker, System.currentTimeMillis())); } } diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java index 407bad6009aa..877028ad9bad 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java @@ -52,7 +52,9 @@ public void setUp() throws Exception @Test public void testGetBrokerStatus() { - EasyMock.expect(coordinatorDynamicConfigSyncer.getInSyncBrokers()).andReturn(Set.of("brok1")).once(); + EasyMock.expect(coordinatorDynamicConfigSyncer.getInSyncBrokers()) + .andReturn(Set.of(new BrokerSyncStatus("host1", 8080, 1000))) + .once(); EasyMock.replay(coordinatorDynamicConfigSyncer); EasyMock.replay(cloneStatusManager); From bd8d02677b7f20600db66b27d776d00e63787a57 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Tue, 22 Apr 2025 10:46:59 +0530 Subject: [PATCH 28/38] Update docs --- docs/api-reference/service-status-api.md | 16 +++-- .../druid/server/http/BrokerSyncStatus.java | 10 +++ .../druid/server/http/ConfigSyncStatus.java | 70 +++++++++++++++++++ .../http/CoordinatorDynamicConfigSyncer.java | 6 +- ...CoordinatorDynamicConfigsResourceTest.java | 18 ++++- 5 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java diff --git a/docs/api-reference/service-status-api.md b/docs/api-reference/service-status-api.md index 47b5e52f1fa4..fd5bbd23f9ff 100644 --- a/docs/api-reference/service-status-api.md +++ b/docs/api-reference/service-status-api.md @@ -713,9 +713,9 @@ Host: http://COORDINATOR_IP:COORDINATOR_PORT { "localhost:8083": { "sourceServer": "localhost:8089", - "status": "LOADING", + "state": "LOADING", "segmentLoadsRemaining": 0, - "segmenetsDropsRemaining": 0, + "segmentDropsRemaining": 0, "bytesRemaining": 0 } } @@ -774,9 +774,15 @@ Host: http://COORDINATOR_IP:COORDINATOR_PORT View the response ```json -[ - "localhost:8082" -] +{ + "inSyncBrokers": [ + { + "host": "localhost", + "port": 8082, + "syncTime": 1745298963900 + } + ] +} ``` diff --git a/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java b/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java index a6d29d1119cb..95eeb1914cde 100644 --- a/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java +++ b/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java @@ -86,4 +86,14 @@ public int hashCode() { return Objects.hash(host, port); } + + @Override + public String toString() + { + return "BrokerSyncStatus{" + + "host='" + host + '\'' + + ", port=" + port + + ", syncTime=" + syncTime + + '}'; + } } diff --git a/server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java b/server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java new file mode 100644 index 000000000000..fa1ab90a34bc --- /dev/null +++ b/server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java @@ -0,0 +1,70 @@ +/* + * 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.server.http; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Objects; +import java.util.Set; + +public class ConfigSyncStatus +{ + private final Set inSyncBrokers; + + @JsonCreator + public ConfigSyncStatus(@JsonProperty("inSyncBrokers") Set inSyncBrokers) + { + this.inSyncBrokers = inSyncBrokers; + } + + @JsonProperty + public Set getInSyncBrokers() + { + return inSyncBrokers; + } + + @Override + public boolean equals(Object o) + { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConfigSyncStatus that = (ConfigSyncStatus) o; + return Objects.equals(inSyncBrokers, that.inSyncBrokers); + } + + @Override + public int hashCode() + { + return Objects.hashCode(inSyncBrokers); + } + + @Override + public String toString() + { + return "ConfigSyncStatus{" + + "inSyncBrokers=" + inSyncBrokers + + '}'; + } +} diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java index f10b3124d35b..8f5fc5d5b3ec 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java @@ -93,9 +93,9 @@ public void broadcastConfigToBrokers() } } - public synchronized Set getInSyncBrokers() + public synchronized ConfigSyncStatus getInSyncBrokers() { - return Set.copyOf(inSyncBrokers); + return new ConfigSyncStatus(Set.copyOf(inSyncBrokers)); } public void onLeaderStart() @@ -186,4 +186,6 @@ private static ServiceLocation convertDiscoveryNodeToServiceLocation(DiscoveryDr "" ); } + + } diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java index 877028ad9bad..e0cdbf6d9608 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java @@ -20,6 +20,7 @@ package org.apache.druid.server.http; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import org.apache.druid.audit.AuditManager; import org.apache.druid.server.coordinator.CloneStatusManager; import org.apache.druid.server.coordinator.CoordinatorConfigManager; @@ -31,7 +32,6 @@ import javax.ws.rs.core.Response; import java.util.Map; -import java.util.Set; public class CoordinatorDynamicConfigsResourceTest { @@ -53,7 +53,14 @@ public void setUp() throws Exception public void testGetBrokerStatus() { EasyMock.expect(coordinatorDynamicConfigSyncer.getInSyncBrokers()) - .andReturn(Set.of(new BrokerSyncStatus("host1", 8080, 1000))) + .andReturn( + new ConfigSyncStatus( + ImmutableSet.of( + new BrokerSyncStatus("host1", 8080, 1000 + ) + ) + ) + ) .once(); EasyMock.replay(coordinatorDynamicConfigSyncer); EasyMock.replay(cloneStatusManager); @@ -67,7 +74,12 @@ public void testGetBrokerStatus() Assert.assertEquals(200, response.getStatus()); - Assert.assertEquals(Set.of("brok1"), response.getEntity()); + ConfigSyncStatus expected = new ConfigSyncStatus( + ImmutableSet.of( + new BrokerSyncStatus("host1", 8080, 1000) + ) + ); + Assert.assertEquals(expected, response.getEntity()); } @Test From bc9906ede72563c82494cd6fa4c21bffb44c35d6 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Wed, 23 Apr 2025 18:02:05 +0530 Subject: [PATCH 29/38] Add javadocs --- docs/api-reference/service-status-api.md | 2 +- .../server/coordinator/CloneStatusManager.java | 12 ++++++++++++ .../server/coordinator/ServerCloneStatus.java | 3 +++ .../druid/server/http/BrokerSyncStatus.java | 16 ++++++++-------- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/docs/api-reference/service-status-api.md b/docs/api-reference/service-status-api.md index fd5bbd23f9ff..70761de262ef 100644 --- a/docs/api-reference/service-status-api.md +++ b/docs/api-reference/service-status-api.md @@ -779,7 +779,7 @@ Host: http://COORDINATOR_IP:COORDINATOR_PORT { "host": "localhost", "port": 8082, - "syncTime": 1745298963900 + "syncTimeInMs": 1745298963900 } ] } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java index de4e78fbff5f..cba92503cb09 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java @@ -25,6 +25,9 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicReference; +/** + * Manager to store and update the status of ongoing cloning operations. + */ public class CloneStatusManager { private final AtomicReference> cloneStatusSnapshot; @@ -34,17 +37,26 @@ public CloneStatusManager() this.cloneStatusSnapshot = new AtomicReference<>(Map.of()); } + /** + * Returns the status of cloning as a map of target server to {@link ServerCloneStatus}. + */ public Map getStatusForAllServers() { return cloneStatusSnapshot.get(); } + /** + * Returns the status of cloning as a {@link ServerCloneStatus} for a specific target server. + */ @Nullable public ServerCloneStatus getStatusForServer(String targetServer) { return cloneStatusSnapshot.get().get(targetServer); } + /** + * Updates the stored status with the provided parameter. + */ public void updateStatus(Map newStatusMap) { cloneStatusSnapshot.set(ImmutableMap.copyOf(newStatusMap)); diff --git a/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java b/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java index 44113585bdd2..e07e9e93b8c8 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java @@ -24,6 +24,9 @@ import java.util.Objects; +/** + * Immutable class which represents the current status of a single clone server. + */ public class ServerCloneStatus { private final String sourceServer; diff --git a/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java b/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java index 95eeb1914cde..04ac4e8bae8a 100644 --- a/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java +++ b/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java @@ -29,25 +29,25 @@ public class BrokerSyncStatus { private final String host; private final int port; - private final long syncTime; + private final long syncTimeInMs; @JsonCreator public BrokerSyncStatus( @JsonProperty("host") String host, @JsonProperty("port") int port, - @JsonProperty("syncTime") long syncTime + @JsonProperty("syncTimeInMs") long syncTimeInMs ) { this.host = host; this.port = port; - this.syncTime = syncTime; + this.syncTimeInMs = syncTimeInMs; } - public BrokerSyncStatus(ServiceLocation broker, long syncTime) + public BrokerSyncStatus(ServiceLocation broker, long syncTimeInMs) { this.host = broker.getHost(); this.port = broker.getTlsPort() > 0 ? broker.getTlsPort() : broker.getPlaintextPort(); - this.syncTime = syncTime; + this.syncTimeInMs = syncTimeInMs; } @JsonProperty @@ -63,9 +63,9 @@ public int getPort() } @JsonProperty - public long getSyncTime() + public long getSyncTimeInMs() { - return syncTime; + return syncTimeInMs; } @Override @@ -93,7 +93,7 @@ public String toString() return "BrokerSyncStatus{" + "host='" + host + '\'' + ", port=" + port + - ", syncTime=" + syncTime + + ", syncTimeInMs=" + syncTimeInMs + '}'; } } From a05e4072c4bdf3632472dd4bee8a476c5144e0d2 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Fri, 25 Apr 2025 15:28:12 +0530 Subject: [PATCH 30/38] Refactor ServerSelector to contain HistoricalFilter --- .../CachingClusteredClientBenchmark.java | 5 ++-- .../DatasourceOptimizerTest.java | 7 +++++- .../movingaverage/MovingAverageQueryTest.java | 5 ---- .../controller/DartTableInputSpecSlicer.java | 5 ++-- .../DartTableInputSpecSlicerTest.java | 4 ++- .../apache/druid/client/BrokerServerView.java | 7 ++++-- .../druid/client/CachingClusteredClient.java | 13 +++------- .../apache/druid/client/ServerViewUtil.java | 2 +- .../druid/client/selector/ServerSelector.java | 13 ++++++---- .../coordinator/CloneStatusManager.java | 8 +++--- .../CoordinatorDynamicConfigsResource.java | 6 ++++- .../druid/client/BrokerServerViewTest.java | 24 ++++++++++-------- ...ingClusteredClientCacheKeyManagerTest.java | 25 +++++++++---------- ...chingClusteredClientFunctionalityTest.java | 5 ++-- .../CachingClusteredClientPerfTest.java | 8 +++--- .../client/CachingClusteredClientTest.java | 23 +++++++++-------- .../druid/client/DirectDruidClientTest.java | 9 ++++--- .../apache/druid/client/SimpleServerView.java | 3 ++- ...ectionCountServerSelectorStrategyTest.java | 7 +++--- .../client/selector/ServerSelectorTest.java | 12 ++++++--- .../selector/TierSelectorStrategyTest.java | 11 ++++---- ...yRunnerBasedOnClusteredClientTestBase.java | 5 ---- .../druid/server/ClientInfoResourceTest.java | 5 ++-- ...CoordinatorDynamicConfigsResourceTest.java | 9 ++++--- ...erSegmentMetadataCacheConcurrencyTest.java | 7 +++++- .../calcite/util/TestTimelineServerView.java | 3 ++- 26 files changed, 129 insertions(+), 102 deletions(-) diff --git a/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java b/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java index 66e19282d66c..df4677c3bc8f 100644 --- a/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java +++ b/benchmarks/src/test/java/org/apache/druid/benchmark/query/CachingClusteredClientBenchmark.java @@ -181,6 +181,7 @@ public class CachingClusteredClientBenchmark private final QuerySegmentSpec basicSchemaIntervalSpec = new MultipleIntervalSegmentSpec( Collections.singletonList(basicSchema.getDataInterval()) ); + private final BrokerViewOfCoordinatorConfig filter = new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()); private final int numProcessingThreads = 4; @@ -227,6 +228,7 @@ public void setup() rowsPerSegment ); queryableIndexes.put(dataSegment, index); + filter.start(); } final DruidProcessingConfig processingConfig = new DruidProcessingConfig() @@ -308,7 +310,6 @@ public int getNumThreads() cachingClusteredClient = new CachingClusteredClient( conglomerate, serverView, - new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()), MapCache.create(0), JSON_MAPPER, new ForegroundCachePopulator(JSON_MAPPER, new CachePopulatorStats(), 0), @@ -522,7 +523,7 @@ void addSegmentToServer(DruidServer server, DataSegment segment) { final ServerSelector selector = selectors.computeIfAbsent( segment.getId().toString(), - k -> new ServerSelector(segment, tierSelectorStrategy) + k -> new ServerSelector(segment, tierSelectorStrategy, filter) ); selector.addServerAndUpdateSegment(servers.get(server), segment); timelines.computeIfAbsent(segment.getDataSource(), k -> new VersionedIntervalTimeline<>(Ordering.natural())) diff --git a/extensions-contrib/materialized-view-selection/src/test/java/org/apache/druid/query/materializedview/DatasourceOptimizerTest.java b/extensions-contrib/materialized-view-selection/src/test/java/org/apache/druid/query/materializedview/DatasourceOptimizerTest.java index 606c6a529587..1ec98359db79 100644 --- a/extensions-contrib/materialized-view-selection/src/test/java/org/apache/druid/query/materializedview/DatasourceOptimizerTest.java +++ b/extensions-contrib/materialized-view-selection/src/test/java/org/apache/druid/query/materializedview/DatasourceOptimizerTest.java @@ -31,6 +31,7 @@ import org.apache.druid.client.BatchServerInventoryView; import org.apache.druid.client.BrokerSegmentWatcherConfig; import org.apache.druid.client.BrokerServerView; +import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.DirectDruidClientFactory; import org.apache.druid.client.DruidServer; import org.apache.druid.client.selector.HighestPriorityTierSelectorStrategy; @@ -58,6 +59,7 @@ import org.apache.druid.segment.realtime.appenderator.SegmentSchemas; import org.apache.druid.server.coordination.DruidServerMetadata; import org.apache.druid.server.coordination.ServerType; +import org.apache.druid.server.coordination.TestCoordinatorClient; import org.apache.druid.server.coordinator.simulate.TestDruidLeaderSelector; import org.apache.druid.server.initialization.ZkPathsConfig; import org.apache.druid.server.metrics.NoopServiceEmitter; @@ -319,12 +321,15 @@ public CallbackAction segmentSchemasAnnounced(SegmentSchemas segmentSchemas) EasyMock.createMock(HttpClient.class) ); + BrokerViewOfCoordinatorConfig filter = new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()); + filter.start(); brokerServerView = new BrokerServerView( druidClientFactory, baseView, new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), new NoopServiceEmitter(), - new BrokerSegmentWatcherConfig() + new BrokerSegmentWatcherConfig(), + filter ); baseView.start(); } diff --git a/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java b/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java index 9ce71fbb8258..caa402a142ec 100644 --- a/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java +++ b/extensions-contrib/moving-average-query/src/test/java/org/apache/druid/query/movingaverage/MovingAverageQueryTest.java @@ -31,7 +31,6 @@ import com.google.inject.multibindings.Multibinder; import com.google.inject.name.Names; import com.google.inject.util.Providers; -import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.CachingClusteredClient; import org.apache.druid.client.DruidServer; import org.apache.druid.client.ImmutableDruidServer; @@ -72,7 +71,6 @@ import org.apache.druid.server.ClientQuerySegmentWalker; import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.SubqueryGuardrailHelper; -import org.apache.druid.server.coordination.TestCoordinatorClient; import org.apache.druid.server.initialization.ServerConfig; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.server.metrics.SubqueryCountStatsProvider; @@ -318,8 +316,6 @@ public long getMaxQueuedBytes() return 0L; } }; - BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig = new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()); - brokerViewOfCoordinatorConfig.start(); CachingClusteredClient baseClient = new CachingClusteredClient( conglomerate, new TimelineServerView() @@ -360,7 +356,6 @@ public void registerServerRemovedCallback(Executor exec, ServerRemovedCallback c } }, - brokerViewOfCoordinatorConfig, MapCache.create(100000), jsonMapper, new ForegroundCachePopulator(jsonMapper, new CachePopulatorStats(), -1), diff --git a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java index 82e07dc10228..9345e5a1d875 100644 --- a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java +++ b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java @@ -25,7 +25,6 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import org.apache.druid.client.QueryableDruidServer; import org.apache.druid.client.TimelineServerView; -import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.java.util.common.ISE; import org.apache.druid.java.util.common.JodaUtils; @@ -165,7 +164,7 @@ public List sliceDynamic( int findWorkerForServerSelector(final ServerSelector serverSelector, final int maxNumSlices) { // Currently, Dart does not support clone query modes, all servers can be queried. - final QueryableDruidServer server = serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE); + final QueryableDruidServer server = serverSelector.pick(null, CloneQueryMode.EXCLUDE); if (server == null) { return UNKNOWN; @@ -283,7 +282,7 @@ static boolean shouldIncludeSegment(final ServerSelector serverSelector) int numOtherServers = 0; // Currently, Dart does not support clone query modes, all servers can be queried. - for (final DruidServerMetadata server : serverSelector.getAllServers(HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.INCLUDE)) { + for (final DruidServerMetadata server : serverSelector.getAllServers(CloneQueryMode.INCLUDE)) { if (SegmentSource.REALTIME.getUsedServerTypes().contains(server.getType())) { numRealtimeServers++; } else { diff --git a/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicerTest.java b/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicerTest.java index 92ce2bd2a1c4..a65c1252c6eb 100644 --- a/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicerTest.java +++ b/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicerTest.java @@ -28,6 +28,7 @@ import org.apache.druid.client.QueryableDruidServer; import org.apache.druid.client.TimelineServerView; import org.apache.druid.client.selector.HighestPriorityTierSelectorStrategy; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.RandomServerSelectorStrategy; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.data.input.StringTuple; @@ -214,7 +215,8 @@ void setUp() final IntList segmentServers = entry.getValue(); final ServerSelector serverSelector = new ServerSelector( dataSegment, - new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()) + new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), + HistoricalFilter.IDENTITY_FILTER ); for (int serverNumber : segmentServers) { final DruidServerMetadata serverMetadata = SERVERS.get(serverNumber); diff --git a/server/src/main/java/org/apache/druid/client/BrokerServerView.java b/server/src/main/java/org/apache/druid/client/BrokerServerView.java index 6eaea5796f52..9e13625b9bb8 100644 --- a/server/src/main/java/org/apache/druid/client/BrokerServerView.java +++ b/server/src/main/java/org/apache/druid/client/BrokerServerView.java @@ -75,6 +75,7 @@ public class BrokerServerView implements TimelineServerView private final Predicate> segmentFilter; private final CountDownLatch initialized = new CountDownLatch(1); private final FilteredServerInventoryView baseView; + private final BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig; @Inject public BrokerServerView( @@ -82,13 +83,15 @@ public BrokerServerView( final FilteredServerInventoryView baseView, final TierSelectorStrategy tierSelectorStrategy, final ServiceEmitter emitter, - final BrokerSegmentWatcherConfig segmentWatcherConfig + final BrokerSegmentWatcherConfig segmentWatcherConfig, + final BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig ) { this.druidClientFactory = directDruidClientFactory; this.baseView = baseView; this.tierSelectorStrategy = tierSelectorStrategy; this.emitter = emitter; + this.brokerViewOfCoordinatorConfig = brokerViewOfCoordinatorConfig; // Validate and set the segment watcher config validateSegmentWatcherConfig(segmentWatcherConfig); @@ -253,7 +256,7 @@ private void serverAddedSegment(final DruidServerMetadata server, final DataSegm log.debug("Adding segment[%s] for server[%s]", segment, server); ServerSelector selector = selectors.get(segmentId); if (selector == null) { - selector = new ServerSelector(segment, tierSelectorStrategy); + selector = new ServerSelector(segment, tierSelectorStrategy, brokerViewOfCoordinatorConfig); VersionedIntervalTimeline timeline = timelines.get(segment.getDataSource()); if (timeline == null) { diff --git a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java index 21c62674ee84..e0c7f0e4e5f9 100644 --- a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java +++ b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java @@ -38,7 +38,6 @@ import org.apache.druid.client.cache.Cache; import org.apache.druid.client.cache.CacheConfig; import org.apache.druid.client.cache.CachePopulator; -import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.guice.annotations.Client; import org.apache.druid.guice.annotations.Merging; @@ -128,13 +127,11 @@ public class CachingClusteredClient implements QuerySegmentWalker private final ForkJoinPool pool; private final QueryScheduler scheduler; private final ServiceEmitter emitter; - private final BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig; @Inject public CachingClusteredClient( QueryRunnerFactoryConglomerate conglomerate, TimelineServerView serverView, - BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig, Cache cache, @Smile ObjectMapper objectMapper, CachePopulator cachePopulator, @@ -157,7 +154,6 @@ public CachingClusteredClient( this.pool = pool; this.scheduler = scheduler; this.emitter = emitter; - this.brokerViewOfCoordinatorConfig = brokerViewOfCoordinatorConfig; if (cacheConfig.isQueryCacheable(Query.GROUP_BY) && (cacheConfig.isUseCache() || cacheConfig.isPopulateCache())) { log.warn( @@ -355,7 +351,7 @@ ClusterQueryResult run( final String prevEtag = (String) query.getContext().get(QueryResource.HEADER_IF_NONE_MATCH); if (prevEtag != null) { @Nullable - final String currentEtag = cacheKeyManager.computeResultLevelCachingEtag(segmentServers, brokerViewOfCoordinatorConfig, cloneQueryMode, queryCacheKey); + final String currentEtag = cacheKeyManager.computeResultLevelCachingEtag(segmentServers, cloneQueryMode, queryCacheKey); if (null != currentEtag) { responseContext.putEntityTag(currentEtag); } @@ -374,7 +370,6 @@ ClusterQueryResult run( final SortedMap> segmentsByServer = groupSegmentsByServer( segmentServers, - brokerViewOfCoordinatorConfig, cloneQueryMode ); LazySequence mergedResultSequence = new LazySequence<>(() -> { @@ -606,14 +601,13 @@ private Cache.NamedKey getCachePopulatorKey(String segmentId, Interval segmentIn private SortedMap> groupSegmentsByServer( Set segments, - HistoricalFilter historicalFilter, CloneQueryMode cloneQueryMode ) { final SortedMap> serverSegments = new TreeMap<>(); for (SegmentServerSelector segmentServer : segments) { final QueryableDruidServer queryableDruidServer = segmentServer.getServer() - .pick(query, historicalFilter, cloneQueryMode); + .pick(query, cloneQueryMode); if (queryableDruidServer == null) { log.makeAlert( @@ -825,7 +819,6 @@ byte[] computeSegmentLevelQueryCacheKey() @Nullable String computeResultLevelCachingEtag( final Set segments, - final HistoricalFilter historicalFilter, final CloneQueryMode cloneQueryMode, @Nullable byte[] queryCacheKey ) @@ -833,7 +826,7 @@ String computeResultLevelCachingEtag( Hasher hasher = Hashing.sha1().newHasher(); boolean hasOnlyHistoricalSegments = true; for (SegmentServerSelector p : segments) { - QueryableDruidServer queryableServer = p.getServer().pick(query, historicalFilter, cloneQueryMode); + QueryableDruidServer queryableServer = p.getServer().pick(query, cloneQueryMode); if (queryableServer == null || !queryableServer.getServer().isSegmentReplicationTarget()) { hasOnlyHistoricalSegments = false; break; diff --git a/server/src/main/java/org/apache/druid/client/ServerViewUtil.java b/server/src/main/java/org/apache/druid/client/ServerViewUtil.java index 3771be4cdfce..234ef84328a1 100644 --- a/server/src/main/java/org/apache/druid/client/ServerViewUtil.java +++ b/server/src/main/java/org/apache/druid/client/ServerViewUtil.java @@ -74,7 +74,7 @@ public static List getTargetLocations( holder.getInterval(), holder.getVersion(), chunk.getChunkNumber() ); long size = selector.getSegment().getSize(); - List candidates = selector.getCandidates(numCandidates, historicalFilter, cloneQueryMode); + List candidates = selector.getCandidates(numCandidates, cloneQueryMode); located.add(new LocatedSegmentDescriptor(descriptor, size, candidates)); } } diff --git a/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java b/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java index 0586f5ebd5b8..1d42ff3dc9ee 100644 --- a/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java +++ b/server/src/main/java/org/apache/druid/client/selector/ServerSelector.java @@ -52,15 +52,19 @@ public class ServerSelector implements Overshadowable private final AtomicReference segment; + private final HistoricalFilter filter; + public ServerSelector( DataSegment segment, - TierSelectorStrategy strategy + TierSelectorStrategy strategy, + HistoricalFilter filter ) { this.segment = new AtomicReference<>(DataSegmentInterner.intern(segment)); this.strategy = strategy; this.historicalServers = new Int2ObjectRBTreeMap<>(strategy.getComparator()); this.realtimeServers = new Int2ObjectRBTreeMap<>(strategy.getComparator()); + this.filter = filter; } public DataSegment getSegment() @@ -124,7 +128,6 @@ public boolean isEmpty() public List getCandidates( final int numCandidates, - final HistoricalFilter filter, final CloneQueryMode cloneQueryMode ) { @@ -145,12 +148,12 @@ public List getCandidates( } return candidates; } else { - return getAllServers(filter, cloneQueryMode); + return getAllServers(cloneQueryMode); } } } - public List getAllServers(HistoricalFilter filter, CloneQueryMode cloneQueryMode) + public List getAllServers(CloneQueryMode cloneQueryMode) { final List servers = new ArrayList<>(); @@ -173,7 +176,7 @@ public List getAllServers(HistoricalFilter filter, CloneQue } @Nullable - public QueryableDruidServer pick(@Nullable Query query, HistoricalFilter filter, CloneQueryMode cloneQueryMode) + public QueryableDruidServer pick(@Nullable Query query, CloneQueryMode cloneQueryMode) { synchronized (this) { if (!historicalServers.isEmpty()) { diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java index cba92503cb09..55a987eb43d6 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java @@ -19,9 +19,11 @@ package org.apache.druid.server.coordinator; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import javax.annotation.Nullable; +import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; @@ -38,11 +40,11 @@ public CloneStatusManager() } /** - * Returns the status of cloning as a map of target server to {@link ServerCloneStatus}. + * Returns the status of cloning as a list of {@link ServerCloneStatus}. */ - public Map getStatusForAllServers() + public List getStatusForAllServers() { - return cloneStatusSnapshot.get(); + return ImmutableList.copyOf(cloneStatusSnapshot.get().values()); } /** diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java index a0a7027fbed9..d42969094406 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java @@ -45,6 +45,8 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import java.util.List; +import java.util.Map; /** */ @@ -163,7 +165,9 @@ public Response getCloneStatus(@QueryParam("targetServer") @Nullable String targ ServerCloneStatus statusForServer = cloneStatusManager.getStatusForServer(targetServer); return Response.ok(ImmutableMap.of(targetServer, statusForServer)).build(); } else { - return Response.ok(cloneStatusManager.getStatusForAllServers()).build(); + // TODO: this or make a class? + List statusForAllServers = cloneStatusManager.getStatusForAllServers(); + return Response.ok(Map.of("cloneStatus", statusForAllServers)).build(); } } } diff --git a/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java b/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java index 67fbd3823073..d0665f600973 100644 --- a/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java +++ b/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java @@ -30,7 +30,6 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.apache.druid.client.selector.HighestPriorityTierSelectorStrategy; -import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.RandomServerSelectorStrategy; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.curator.CuratorTestBase; @@ -47,6 +46,7 @@ import org.apache.druid.segment.realtime.appenderator.SegmentSchemas; import org.apache.druid.server.coordination.DruidServerMetadata; import org.apache.druid.server.coordination.ServerType; +import org.apache.druid.server.coordination.TestCoordinatorClient; import org.apache.druid.server.initialization.ZkPathsConfig; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.timeline.DataSegment; @@ -81,17 +81,20 @@ public class BrokerServerViewTest extends CuratorTestBase private BatchServerInventoryView baseView; private BrokerServerView brokerServerView; + private BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig; public BrokerServerViewTest() { jsonMapper = TestHelper.makeJsonMapper(); zkPathsConfig = new ZkPathsConfig(); + brokerViewOfCoordinatorConfig = new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()); } @Before public void setUp() throws Exception { setupServerAndCurator(); + brokerViewOfCoordinatorConfig.start(); curator.start(); curator.blockUntilConnected(); } @@ -130,7 +133,7 @@ public void testSingleServerAddedRemovedSegment() throws Exception ServerSelector selector = (actualPartitionHolder.iterator().next()).getObject(); Assert.assertFalse(selector.isEmpty()); Assert.assertEquals(segment, selector.getSegment()); - Assert.assertEquals(druidServer, selector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE).getServer()); + Assert.assertEquals(druidServer, selector.pick(null, CloneQueryMode.EXCLUDE).getServer()); Assert.assertNotNull(timeline.findChunk(intervals, "v1", partition)); unannounceSegmentForServer(druidServer, segment, zkPathsConfig); @@ -389,9 +392,9 @@ public void testMultipleTiers() throws Exception // Verify that the ServerSelector always picks Tier 1 for (int i = 0; i < 5; ++i) { - Assert.assertEquals(server21, selector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE).getServer()); + Assert.assertEquals(server21, selector.pick(null, CloneQueryMode.EXCLUDE).getServer()); } - Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDE)); } @Test @@ -449,9 +452,9 @@ public void testRealtimeTasksNotWatched() throws Exception // Verify that the ServerSelector always picks the Historical server for (int i = 0; i < 5; ++i) { - Assert.assertEquals(historicalServer, selector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE).getServer()); + Assert.assertEquals(historicalServer, selector.pick(null, CloneQueryMode.EXCLUDE).getServer()); } - Assert.assertEquals(Collections.singletonList(historicalServer.getMetadata()), selector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(Collections.singletonList(historicalServer.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDE)); } @Test @@ -511,9 +514,9 @@ public void testIgnoredTiers() throws Exception // Verify that the ServerSelector always picks Tier 1 for (int i = 0; i < 5; ++i) { - Assert.assertEquals(server21, selector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE).getServer()); + Assert.assertEquals(server21, selector.pick(null, CloneQueryMode.EXCLUDE).getServer()); } - Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDE)); } @Test(expected = ISE.class) @@ -593,7 +596,7 @@ private void assertValues( ServerSelector selector = ((SingleElementPartitionChunk) actualPartitionHolder.iterator() .next()).getObject(); Assert.assertFalse(selector.isEmpty()); - Assert.assertEquals(expectedPair.rhs.rhs.lhs, selector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE).getServer()); + Assert.assertEquals(expectedPair.rhs.rhs.lhs, selector.pick(null, CloneQueryMode.EXCLUDE).getServer()); Assert.assertEquals(expectedPair.rhs.rhs.rhs, selector.getSegment()); } } @@ -687,7 +690,8 @@ public Set getIgnoredTiers() { return ignoredTiers; } - } + }, + brokerViewOfCoordinatorConfig ); baseView.start(); diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java index e3dfcb7cbfa3..e4660e0ede1b 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java @@ -22,7 +22,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.primitives.Bytes; -import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.query.CacheStrategy; import org.apache.druid.query.CloneQueryMode; @@ -88,7 +87,7 @@ public void testComputeEtag_nonHistorical() makeHistoricalServerSelector(0), makeRealtimeServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); + String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); Assert.assertNull(actual); } @@ -101,14 +100,14 @@ public void testComputeEtag_DifferentHistoricals() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); Assert.assertNotNull(actual1); selectors = ImmutableSet.of( makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); Assert.assertNotNull(actual2); Assert.assertEquals("cache key should not change for same server selectors", actual1, actual2); @@ -116,7 +115,7 @@ public void testComputeEtag_DifferentHistoricals() makeHistoricalServerSelector(2), makeHistoricalServerSelector(1) ); - String actual3 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); + String actual3 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); Assert.assertNotNull(actual3); Assert.assertNotEquals(actual1, actual3); } @@ -130,10 +129,10 @@ public void testComputeEtag_DifferentQueryCacheKey() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, new byte[]{1, 2}); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, new byte[]{1, 2}); Assert.assertNotNull(actual1); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, new byte[]{3, 4}); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, new byte[]{3, 4}); Assert.assertNotNull(actual2); Assert.assertNotEquals(actual1, actual2); } @@ -148,14 +147,14 @@ public void testComputeEtag_nonJoinDataSource() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, FULL_QUERY_CACHE_KEY); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, FULL_QUERY_CACHE_KEY); Assert.assertNotNull(actual1); selectors = ImmutableSet.of( makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, null); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, null); Assert.assertNotNull(actual2); Assert.assertEquals(actual1, actual2); } @@ -171,7 +170,7 @@ public void testComputeEtag_joinWithUnsupportedCaching() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, null); Assert.assertNull(actual); } @@ -189,7 +188,7 @@ public void testComputeEtag_noEffectifBySegment() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, null); Assert.assertNotNull(actual); } @@ -208,7 +207,7 @@ public void testComputeEtag_noEffectIfUseAndPopulateFalse() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, null); Assert.assertNotNull(actual); } @@ -305,7 +304,7 @@ private SegmentServerSelector makeServerSelector(boolean isHistorical, int parti 0 ); expect(server.isSegmentReplicationTarget()).andReturn(isHistorical).anyTimes(); - expect(serverSelector.pick(query, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)).andReturn(queryableDruidServer).anyTimes(); + expect(serverSelector.pick(query, CloneQueryMode.EXCLUDE)).andReturn(queryableDruidServer).anyTimes(); expect(queryableDruidServer.getServer()).andReturn(server).anyTimes(); expect(serverSelector.getSegment()).andReturn(segment).anyTimes(); replay(serverSelector, queryableDruidServer, server); diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java index 850a82b292e8..ae4c4e8a5ab5 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java @@ -30,6 +30,7 @@ import org.apache.druid.client.cache.CachePopulatorStats; import org.apache.druid.client.cache.ForegroundCachePopulator; import org.apache.druid.client.cache.MapCache; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.client.selector.TierSelectorStrategy; import org.apache.druid.guice.http.DruidHttpClientConfig; @@ -213,7 +214,8 @@ public List pick( ) ); } - } + }, + HistoricalFilter.IDENTITY_FILTER ) )); } @@ -269,7 +271,6 @@ public void registerServerRemovedCallback(Executor exec, ServerRemovedCallback c } }, - new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()), cache, OBJECT_MAPPER, cachePopulator, diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java index bde66a7425cf..c944146cb5a9 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientPerfTest.java @@ -87,6 +87,8 @@ public void testGetQueryRunnerForSegments_singleIntervalLargeSegments() final List segmentDescriptors = new ArrayList<>(segmentCount); final List dataSegments = new ArrayList<>(segmentCount); final VersionedIntervalTimeline timeline = new VersionedIntervalTimeline<>(Ordering.natural()); + final BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig = new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()); + brokerViewOfCoordinatorConfig.start(); final DruidServer server = new DruidServer( "server", "localhost:9000", @@ -106,7 +108,8 @@ public void testGetQueryRunnerForSegments_singleIntervalLargeSegments() Iterators.transform(dataSegments.iterator(), segment -> { ServerSelector ss = new ServerSelector( segment, - new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()) + new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), + brokerViewOfCoordinatorConfig ); ss.addServerAndUpdateSegment(new QueryableDruidServer( server, @@ -129,12 +132,9 @@ public void testGetQueryRunnerForSegments_singleIntervalLargeSegments() Mockito.doReturn(Optional.of(timeline)).when(serverView).getTimeline(any()); Mockito.doReturn(new MockQueryRunner()).when(serverView).getQueryRunner(any()); - BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig = new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()); - brokerViewOfCoordinatorConfig.start(); CachingClusteredClient cachingClusteredClient = new CachingClusteredClient( new MockQueryRunnerFactoryConglomerate(), serverView, - brokerViewOfCoordinatorConfig, MapCache.create(1024), TestHelper.makeJsonMapper(), Mockito.mock(CachePopulator.class), diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java index a3b1edaededf..d42b44b2db6c 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java @@ -44,6 +44,7 @@ import org.apache.druid.client.cache.ForegroundCachePopulator; import org.apache.druid.client.cache.MapCache; import org.apache.druid.client.selector.HighestPriorityTierSelectorStrategy; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.RandomServerSelectorStrategy; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.guice.http.DruidHttpClientConfig; @@ -115,7 +116,6 @@ import org.apache.druid.server.QueryScheduler; import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.coordination.ServerType; -import org.apache.druid.server.coordination.TestCoordinatorClient; import org.apache.druid.server.initialization.ServerConfig; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.server.scheduling.ManualQueryPrioritizationStrategy; @@ -549,7 +549,8 @@ public void testCachingOverBulkLimitEnforcesLimit() EasyMock.replay(dataSegment); final ServerSelector selector = new ServerSelector( dataSegment, - new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()) + new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), + HistoricalFilter.IDENTITY_FILTER ); selector.addServerAndUpdateSegment(new QueryableDruidServer(lastServer, null), dataSegment); timeline.add(interval, "v", new SingleElementPartitionChunk<>(selector)); @@ -1752,7 +1753,8 @@ private ServerSelector makeMockHashBasedSelector( ServerSelector selector = new ServerSelector( segment, - new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()) + new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), + HistoricalFilter.IDENTITY_FILTER ); selector.addServerAndUpdateSegment(new QueryableDruidServer(server, null), segment); return selector; @@ -1785,7 +1787,8 @@ private ServerSelector makeMockSingleDimensionSelector( ServerSelector selector = new ServerSelector( segment, - new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()) + new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), + HistoricalFilter.IDENTITY_FILTER ); selector.addServerAndUpdateSegment(new QueryableDruidServer(server, null), segment); return selector; @@ -2232,7 +2235,8 @@ private List> populateTimeline( EasyMock.replay(mockSegment); ServerSelector selector = new ServerSelector( expectation.getSegment(), - new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()) + new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), + HistoricalFilter.IDENTITY_FILTER ); selector.addServerAndUpdateSegment(new QueryableDruidServer(lastServer, null), selector.getSegment()); EasyMock.reset(mockSegment); @@ -2605,8 +2609,6 @@ protected CachingClusteredClient makeClient( final int mergeLimit ) { - BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig = new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()); - brokerViewOfCoordinatorConfig.start(); return new CachingClusteredClient( conglomerateRule.getConglomerate(), new TimelineServerView() @@ -2646,7 +2648,6 @@ public void registerServerRemovedCallback(Executor exec, ServerRemovedCallback c } }, - brokerViewOfCoordinatorConfig, cache, JSON_MAPPER, cachePopulator, @@ -3040,7 +3041,8 @@ public void testIfNoneMatch() ); final ServerSelector selector = new ServerSelector( dataSegment, - new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()) + new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), + HistoricalFilter.IDENTITY_FILTER ); selector.addServerAndUpdateSegment(new QueryableDruidServer(servers[0], null), dataSegment); timeline.add(interval, "ver", new SingleElementPartitionChunk<>(selector)); @@ -3081,7 +3083,8 @@ public void testEtagforDifferentQueryInterval() ); final ServerSelector selector = new ServerSelector( dataSegment, - new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()) + new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), + HistoricalFilter.IDENTITY_FILTER ); selector.addServerAndUpdateSegment(new QueryableDruidServer(servers[0], null), dataSegment); timeline.add(interval, "ver", new SingleElementPartitionChunk<>(selector)); diff --git a/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java b/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java index e8abaf120852..e8ac181178ca 100644 --- a/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java +++ b/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java @@ -27,7 +27,6 @@ import com.google.common.util.concurrent.SettableFuture; import org.apache.druid.client.selector.ConnectionCountServerSelectorStrategy; import org.apache.druid.client.selector.HighestPriorityTierSelectorStrategy; -import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.jackson.DefaultObjectMapper; import org.apache.druid.java.util.common.DateTimes; @@ -50,6 +49,7 @@ import org.apache.druid.query.timeboundary.TimeBoundaryQuery; import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.coordination.ServerType; +import org.apache.druid.server.coordination.TestCoordinatorClient; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.partition.NoneShardSpec; @@ -105,10 +105,13 @@ public class DirectDruidClientTest @Before public void setup() { + final BrokerViewOfCoordinatorConfig filter = new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()); + filter.start(); httpClient = EasyMock.createMock(HttpClient.class); serverSelector = new ServerSelector( dataSegment, - new HighestPriorityTierSelectorStrategy(new ConnectionCountServerSelectorStrategy()) + new HighestPriorityTierSelectorStrategy(new ConnectionCountServerSelectorStrategy()), + filter ); queryCancellationExecutor = Execs.scheduledSingleThreaded("query-cancellation-executor"); client = new DirectDruidClient( @@ -245,7 +248,7 @@ public void testRun() throws Exception Assert.assertEquals(2, client2.getNumOpenConnections()); - Assert.assertEquals(serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE), queryableDruidServer2); + Assert.assertEquals(serverSelector.pick(null, CloneQueryMode.EXCLUDE), queryableDruidServer2); EasyMock.verify(httpClient); } diff --git a/server/src/test/java/org/apache/druid/client/SimpleServerView.java b/server/src/test/java/org/apache/druid/client/SimpleServerView.java index 523bba766ba3..f7c93f2c9e27 100644 --- a/server/src/test/java/org/apache/druid/client/SimpleServerView.java +++ b/server/src/test/java/org/apache/druid/client/SimpleServerView.java @@ -23,6 +23,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Ordering; import org.apache.druid.client.selector.HighestPriorityTierSelectorStrategy; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.RandomServerSelectorStrategy; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.client.selector.TierSelectorStrategy; @@ -113,7 +114,7 @@ private void addSegmentToServer(DruidServer server, DataSegment segment) { final ServerSelector selector = selectors.computeIfAbsent( segment.getId().toString(), - k -> new ServerSelector(segment, tierSelectorStrategy) + k -> new ServerSelector(segment, tierSelectorStrategy, HistoricalFilter.IDENTITY_FILTER) ); selector.addServerAndUpdateSegment(servers.get(server), segment); // broker needs to skip tombstones in its timelines diff --git a/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java b/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java index 4ac309f5a762..df8b6fd42cca 100644 --- a/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java +++ b/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java @@ -51,7 +51,7 @@ public void testDifferentConnectionCount() ServerSelector serverSelector = initSelector(s1, s2, s3); for (int i = 0; i < 100; ++i) { - Assert.assertEquals(s2, serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(s2, serverSelector.pick(null, CloneQueryMode.EXCLUDE)); } } @@ -64,7 +64,7 @@ public void testBalancerTieBreaking() Set pickedServers = new HashSet<>(); for (int i = 0; i < 100; ++i) { - pickedServers.add(serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE).getServer().getName()); + pickedServers.add(serverSelector.pick(null, CloneQueryMode.EXCLUDE).getServer().getName()); } Assert.assertTrue( "Multiple servers should be selected when the number of connections is equal.", @@ -104,7 +104,8 @@ private ServerSelector initSelector(QueryableDruidServer... servers) new NumberedShardSpec(0, 0), 0, 0L - ), strategy + ), strategy, + HistoricalFilter.IDENTITY_FILTER ); List serverList = new ArrayList<>(Arrays.asList(servers)); Collections.shuffle(serverList); diff --git a/server/src/test/java/org/apache/druid/client/selector/ServerSelectorTest.java b/server/src/test/java/org/apache/druid/client/selector/ServerSelectorTest.java index e652ca2c68c2..5b351b092f48 100644 --- a/server/src/test/java/org/apache/druid/client/selector/ServerSelectorTest.java +++ b/server/src/test/java/org/apache/druid/client/selector/ServerSelectorTest.java @@ -65,7 +65,8 @@ public void testSegmentUpdate() .binaryVersion(9) .size(0) .build(), - new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()) + new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), + HistoricalFilter.IDENTITY_FILTER ); selector.addServerAndUpdateSegment( @@ -108,7 +109,8 @@ public void testSegmentCannotBeNull() { final ServerSelector selector = new ServerSelector( null, - new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()) + new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), + HistoricalFilter.IDENTITY_FILTER ); } @@ -132,7 +134,8 @@ public void testSegmentWithNoData() .binaryVersion(9) .size(0) .build(), - new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()) + new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), + HistoricalFilter.IDENTITY_FILTER ); Assert.assertFalse(selector.hasData()); } @@ -159,7 +162,8 @@ public void testSegmentWithData() .binaryVersion(9) .size(0) .build(), - new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()) + new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), + HistoricalFilter.IDENTITY_FILTER ); Assert.assertTrue(selector.hasData()); } diff --git a/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java b/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java index f84914dd893d..765752cfd43a 100644 --- a/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java +++ b/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java @@ -227,7 +227,8 @@ private void testTierSelectorStrategy( 0, 0L ), - tierSelectorStrategy + tierSelectorStrategy, + HistoricalFilter.IDENTITY_FILTER ); List servers = new ArrayList<>(Arrays.asList(expectedSelection)); @@ -241,10 +242,10 @@ private void testTierSelectorStrategy( serverSelector.addServerAndUpdateSegment(server, serverSelector.getSegment()); } - Assert.assertEquals(expectedSelection[0], serverSelector.pick(null, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); - Assert.assertEquals(expectedSelection[0], serverSelector.pick(EasyMock.createMock(Query.class), HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); - Assert.assertEquals(expectedCandidates, serverSelector.getCandidates(-1, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); - Assert.assertEquals(expectedCandidates.subList(0, 2), serverSelector.getCandidates(2, HistoricalFilter.IDENTITY_FILTER, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(expectedSelection[0], serverSelector.pick(null, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(expectedSelection[0], serverSelector.pick(EasyMock.createMock(Query.class), CloneQueryMode.EXCLUDE)); + Assert.assertEquals(expectedCandidates, serverSelector.getCandidates(-1, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(expectedCandidates.subList(0, 2), serverSelector.getCandidates(2, CloneQueryMode.EXCLUDE)); } @Test diff --git a/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java b/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java index 54e5eb6b7af7..76a63442e3ee 100644 --- a/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java +++ b/server/src/test/java/org/apache/druid/query/QueryRunnerBasedOnClusteredClientTestBase.java @@ -23,7 +23,6 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.CachingClusteredClient; import org.apache.druid.client.DirectDruidClient; import org.apache.druid.client.DruidServer; @@ -51,7 +50,6 @@ import org.apache.druid.segment.generator.GeneratorSchemaInfo; import org.apache.druid.segment.generator.SegmentGenerator; import org.apache.druid.server.QueryStackTests; -import org.apache.druid.server.coordination.TestCoordinatorClient; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.partition.NumberedShardSpec; @@ -123,12 +121,9 @@ public void setupTestBase() segmentGenerator = new SegmentGenerator(); httpClient = new TestHttpClient(objectMapper); simpleServerView = new SimpleServerView(conglomerate, objectMapper, httpClient); - BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig = new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()); - brokerViewOfCoordinatorConfig.start(); cachingClusteredClient = new CachingClusteredClient( conglomerate, simpleServerView, - brokerViewOfCoordinatorConfig, MapCache.create(0), objectMapper, new ForegroundCachePopulator(objectMapper, new CachePopulatorStats(), 0), diff --git a/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java b/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java index 43f62f94175f..ca8e238a2220 100644 --- a/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java @@ -27,6 +27,7 @@ import org.apache.druid.client.FilteredServerInventoryView; import org.apache.druid.client.TimelineServerView; import org.apache.druid.client.selector.HighestPriorityTierSelectorStrategy; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.RandomServerSelectorStrategy; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.java.util.common.Intervals; @@ -368,7 +369,7 @@ private void addSegment( .size(1) .build(); server.addDataSegment(segment); - ServerSelector ss = new ServerSelector(segment, new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy())); + ServerSelector ss = new ServerSelector(segment, new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), HistoricalFilter.IDENTITY_FILTER); timeline.add(Intervals.of(interval), version, new SingleElementPartitionChunk<>(ss)); } @@ -392,7 +393,7 @@ private void addSegmentWithShardSpec( .size(1) .build(); server.addDataSegment(segment); - ServerSelector ss = new ServerSelector(segment, new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy())); + ServerSelector ss = new ServerSelector(segment, new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), HistoricalFilter.IDENTITY_FILTER); timeline.add(Intervals.of(interval), version, shardSpec.createChunk(ss)); } diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java index e0cdbf6d9608..3f58adee0cbd 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java @@ -19,7 +19,7 @@ package org.apache.druid.server.http; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import org.apache.druid.audit.AuditManager; import org.apache.druid.server.coordinator.CloneStatusManager; @@ -31,6 +31,7 @@ import org.junit.Test; import javax.ws.rs.core.Response; +import java.util.List; import java.util.Map; public class CoordinatorDynamicConfigsResourceTest @@ -85,9 +86,9 @@ public void testGetBrokerStatus() @Test public void testGetCloneStatus() { - Map statusMetrics = ImmutableMap.of( - "hist1", new ServerCloneStatus("hist3", ServerCloneStatus.State.LOADING, 2, 0, 1000), - "hist2", ServerCloneStatus.unknown("hist4") + List statusMetrics = ImmutableList.of( + new ServerCloneStatus("hist3", ServerCloneStatus.State.LOADING, 2, 0, 1000), + ServerCloneStatus.unknown("hist4") ); EasyMock.expect(cloneStatusManager.getStatusForAllServers()).andReturn(statusMetrics).once(); diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/schema/BrokerSegmentMetadataCacheConcurrencyTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/schema/BrokerSegmentMetadataCacheConcurrencyTest.java index eb92a090d62b..f1a8dd0be1c1 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/schema/BrokerSegmentMetadataCacheConcurrencyTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/schema/BrokerSegmentMetadataCacheConcurrencyTest.java @@ -26,6 +26,7 @@ import com.google.common.collect.Sets; import org.apache.druid.client.BrokerSegmentWatcherConfig; import org.apache.druid.client.BrokerServerView; +import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.DirectDruidClient; import org.apache.druid.client.DirectDruidClientFactory; import org.apache.druid.client.DruidServer; @@ -58,6 +59,7 @@ import org.apache.druid.server.SpecificSegmentsQuerySegmentWalker; import org.apache.druid.server.coordination.DruidServerMetadata; import org.apache.druid.server.coordination.ServerType; +import org.apache.druid.server.coordination.TestCoordinatorClient; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.server.security.NoopEscalator; import org.apache.druid.timeline.DataSegment; @@ -387,12 +389,15 @@ private static BrokerServerView newBrokerServerView(FilteredServerInventoryView .anyTimes(); EasyMock.replay(druidClientFactory); + BrokerViewOfCoordinatorConfig filter = new BrokerViewOfCoordinatorConfig(new TestCoordinatorClient()); + filter.start(); return new BrokerServerView( druidClientFactory, baseView, new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()), new NoopServiceEmitter(), - new BrokerSegmentWatcherConfig() + new BrokerSegmentWatcherConfig(), + filter ); } diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/util/TestTimelineServerView.java b/sql/src/test/java/org/apache/druid/sql/calcite/util/TestTimelineServerView.java index 88df3b80a4e5..a23cefacb4fa 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/util/TestTimelineServerView.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/util/TestTimelineServerView.java @@ -26,6 +26,7 @@ import org.apache.druid.client.ImmutableDruidServer; import org.apache.druid.client.TimelineServerView; import org.apache.druid.client.selector.HighestPriorityTierSelectorStrategy; +import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.RandomServerSelectorStrategy; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.client.selector.TierSelectorStrategy; @@ -108,7 +109,7 @@ public Optional> getTimeline(Ta Comparator.naturalOrder() ); TierSelectorStrategy st = new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy()); - ServerSelector sss = new ServerSelector(segment, st); + ServerSelector sss = new ServerSelector(segment, st, HistoricalFilter.IDENTITY_FILTER); PartitionChunk partitionChunk = new SingleElementPartitionChunk(sss); timelineLookup.add(segment.getInterval(), segment.getVersion(), partitionChunk); From bc85133edf2cb29c5c07525f2b7707e08c15f69b Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Sun, 27 Apr 2025 16:28:13 +0530 Subject: [PATCH 31/38] Refactor to address comments --- .../controller/DartTableInputSpecSlicer.java | 4 +- .../apache/druid/query/CloneQueryMode.java | 6 +-- .../org/apache/druid/query/QueryContexts.java | 2 +- .../apache/druid/query/QueryContextsTest.java | 2 +- .../client/BrokerViewOfCoordinatorConfig.java | 21 +++++----- .../druid/client/broker/BrokerClient.java | 2 +- .../druid/client/broker/BrokerClientImpl.java | 2 +- ....java => BrokerDynamicConfigResource.java} | 6 +-- .../coordinator/CloneStatusManager.java | 3 +- .../server/coordinator/ServerCloneStatus.java | 42 +++++++++++++------ .../coordinator/duty/CloneHistoricals.java | 6 +-- .../druid/server/http/ConfigSyncStatus.java | 16 +++---- .../http/CoordinatorDynamicConfigSyncer.java | 2 +- .../CoordinatorDynamicConfigsResource.java | 3 +- .../druid/client/BrokerServerViewTest.java | 16 +++---- .../BrokerViewOfCoordinatorConfigTest.java | 2 +- ...ingClusteredClientCacheKeyManagerTest.java | 24 +++++------ ...chingClusteredClientFunctionalityTest.java | 1 - .../druid/client/DirectDruidClientTest.java | 2 +- ...ectionCountServerSelectorStrategyTest.java | 4 +- .../selector/TierSelectorStrategyTest.java | 8 ++-- .../coordinator/ServerCloneStatusTest.java | 2 +- ...CoordinatorDynamicConfigsResourceTest.java | 10 ++--- .../java/org/apache/druid/cli/CliBroker.java | 4 +- 24 files changed, 103 insertions(+), 87 deletions(-) rename server/src/main/java/org/apache/druid/server/{DruidInternalDynamicConfigResource.java => BrokerDynamicConfigResource.java} (92%) diff --git a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java index 9345e5a1d875..bf6b81c7dd0a 100644 --- a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java +++ b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java @@ -164,7 +164,7 @@ public List sliceDynamic( int findWorkerForServerSelector(final ServerSelector serverSelector, final int maxNumSlices) { // Currently, Dart does not support clone query modes, all servers can be queried. - final QueryableDruidServer server = serverSelector.pick(null, CloneQueryMode.EXCLUDE); + final QueryableDruidServer server = serverSelector.pick(null, CloneQueryMode.EXCLUDE_CLONES); if (server == null) { return UNKNOWN; @@ -282,7 +282,7 @@ static boolean shouldIncludeSegment(final ServerSelector serverSelector) int numOtherServers = 0; // Currently, Dart does not support clone query modes, all servers can be queried. - for (final DruidServerMetadata server : serverSelector.getAllServers(CloneQueryMode.INCLUDE)) { + for (final DruidServerMetadata server : serverSelector.getAllServers(CloneQueryMode.INCLUDE_CLONES)) { if (SegmentSource.REALTIME.getUsedServerTypes().contains(server.getType())) { numRealtimeServers++; } else { diff --git a/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java b/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java index 49259749679a..d0287dfe8cc2 100644 --- a/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java +++ b/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java @@ -31,15 +31,15 @@ public enum CloneQueryMode * For each ongoing cloning, do not query the source server that is being cloned. Other servers which are not * participating in any cloning will still be queried. */ - CLONES_PREFERRED("clonesPreferred"), + PREFER_CLONES("preferClones"), /** * Consider both clones and their source servers for querying. */ - INCLUDE("includeClones"), + INCLUDE_CLONES("includeClones"), /** * Do not query clone servers. */ - EXCLUDE("excludeClones"); + EXCLUDE_CLONES("excludeClones"); private final String name; diff --git a/processing/src/main/java/org/apache/druid/query/QueryContexts.java b/processing/src/main/java/org/apache/druid/query/QueryContexts.java index cef3051b6c74..dc7bcf1163be 100644 --- a/processing/src/main/java/org/apache/druid/query/QueryContexts.java +++ b/processing/src/main/java/org/apache/druid/query/QueryContexts.java @@ -150,7 +150,7 @@ public class QueryContexts public static final boolean DEFAULT_ENABLE_JOIN_FILTER_PUSH_DOWN = true; public static final boolean DEFAULT_ENABLE_JOIN_FILTER_REWRITE = true; public static final boolean DEFAULT_ENABLE_JOIN_FILTER_REWRITE_VALUE_COLUMN_FILTERS = false; - public static final CloneQueryMode DEFAULT_CLONE_QUERY_MODE = CloneQueryMode.EXCLUDE; + public static final CloneQueryMode DEFAULT_CLONE_QUERY_MODE = CloneQueryMode.EXCLUDE_CLONES; public static final boolean DEFAULT_ENABLE_REWRITE_JOIN_TO_FILTER = true; public static final long DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE = 10000; public static final boolean DEFAULT_ENABLE_SQL_JOIN_LEFT_SCAN_DIRECT = false; diff --git a/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java b/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java index 3c7ab7f9913e..99ef2fad8dd0 100644 --- a/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java +++ b/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java @@ -148,7 +148,7 @@ public void testDefaultPlanTimeBoundarySql() public void testDefaultCloneQueryMode() { Assert.assertEquals( - CloneQueryMode.EXCLUDE, + CloneQueryMode.EXCLUDE_CLONES, QueryContext.empty().getCloneQueryMode() ); } diff --git a/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java index 20b1cd3f6caa..79da551078e5 100644 --- a/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java +++ b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java @@ -25,10 +25,11 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap; import org.apache.druid.client.coordinator.CoordinatorClient; import org.apache.druid.client.selector.HistoricalFilter; +import org.apache.druid.error.DruidException; import org.apache.druid.java.util.common.lifecycle.LifecycleStart; import org.apache.druid.java.util.common.logger.Logger; import org.apache.druid.query.CloneQueryMode; -import org.apache.druid.server.DruidInternalDynamicConfigResource; +import org.apache.druid.server.BrokerDynamicConfigResource; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; import javax.validation.constraints.NotNull; @@ -39,7 +40,7 @@ /** * Broker view of the coordinator dynamic configuration, and its derived values such as target and source clone servers. * This class is registered as a managed lifecycle to fetch the coordinator dynamic configuration on startup. Further - * updates are handled through {@link DruidInternalDynamicConfigResource}. + * updates are handled through {@link BrokerDynamicConfigResource}. */ public class BrokerViewOfCoordinatorConfig implements HistoricalFilter { @@ -59,7 +60,7 @@ public BrokerViewOfCoordinatorConfig(CoordinatorClient coordinatorClient) this.coordinatorClient = coordinatorClient; } - public synchronized CoordinatorDynamicConfig getDynamicConfiguration() + public synchronized CoordinatorDynamicConfig getDynamicConfig() { return config; } @@ -85,12 +86,12 @@ public void start() CoordinatorDynamicConfig coordinatorDynamicConfig = coordinatorClient.getCoordinatorDynamicConfig().get(); setDynamicConfig(coordinatorDynamicConfig); - log.info("Successfully initialized dynamic config: [%s]", coordinatorDynamicConfig); + log.info("Successfully fetched coordinator dynamic config[%s].", coordinatorDynamicConfig); } catch (Exception e) { // If the fetch fails, the broker should not serve queries. Throw the exception and try again on restart. log.error(e, "Failed to initialize coordinator dynamic config"); - throw new RuntimeException(e); + throw new RuntimeException("Failed to initialize coordinator dynamic config", e); } } @@ -122,17 +123,17 @@ public Int2ObjectRBTreeMap> getQueryableServers( private synchronized Set getCurrentServersToIgnore(CloneQueryMode cloneQueryMode) { switch (cloneQueryMode) { - case CLONES_PREFERRED: + case PREFER_CLONES: // Remove servers being cloned targets, so that clones are queried. return serversBeingCloned; - case EXCLUDE: - // Remove clones, so that targets are queried. + case EXCLUDE_CLONES: + // Remove clones, so that only source servers are queried. return cloneServers; - case INCLUDE: + case INCLUDE_CLONES: // Don't remove either return ImmutableSet.of(); default: - throw new IllegalStateException("Unexpected value: " + cloneQueryMode); + throw DruidException.defensive("Unexpected value: " + cloneQueryMode); } } } diff --git a/server/src/main/java/org/apache/druid/client/broker/BrokerClient.java b/server/src/main/java/org/apache/druid/client/broker/BrokerClient.java index 9cb519143d87..7faa2ecd9658 100644 --- a/server/src/main/java/org/apache/druid/client/broker/BrokerClient.java +++ b/server/src/main/java/org/apache/druid/client/broker/BrokerClient.java @@ -58,5 +58,5 @@ public interface BrokerClient /** * Updates the broker with the given {@link CoordinatorDynamicConfig}. */ - ListenableFuture updateDynamicConfig(CoordinatorDynamicConfig config); + ListenableFuture updateCoordinatorDynamicConfig(CoordinatorDynamicConfig config); } diff --git a/server/src/main/java/org/apache/druid/client/broker/BrokerClientImpl.java b/server/src/main/java/org/apache/druid/client/broker/BrokerClientImpl.java index 0217e86144be..3bce514c9801 100644 --- a/server/src/main/java/org/apache/druid/client/broker/BrokerClientImpl.java +++ b/server/src/main/java/org/apache/druid/client/broker/BrokerClientImpl.java @@ -100,7 +100,7 @@ public ListenableFuture> fetchExplainPlan(final ClientSqlQuery } @Override - public ListenableFuture updateDynamicConfig(CoordinatorDynamicConfig config) + public ListenableFuture updateCoordinatorDynamicConfig(CoordinatorDynamicConfig config) { final RequestBuilder requestBuilder = new RequestBuilder(HttpMethod.POST, "/druid-internal/v1/config/coordinator") diff --git a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java b/server/src/main/java/org/apache/druid/server/BrokerDynamicConfigResource.java similarity index 92% rename from server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java rename to server/src/main/java/org/apache/druid/server/BrokerDynamicConfigResource.java index d9e9573715a0..82dba394fee3 100644 --- a/server/src/main/java/org/apache/druid/server/DruidInternalDynamicConfigResource.java +++ b/server/src/main/java/org/apache/druid/server/BrokerDynamicConfigResource.java @@ -34,12 +34,12 @@ import javax.ws.rs.core.Response; @Path("/druid-internal/v1/config") -public class DruidInternalDynamicConfigResource +public class BrokerDynamicConfigResource { private final BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig; @Inject - public DruidInternalDynamicConfigResource(BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig) + public BrokerDynamicConfigResource(BrokerViewOfCoordinatorConfig brokerViewOfCoordinatorConfig) { this.brokerViewOfCoordinatorConfig = brokerViewOfCoordinatorConfig; } @@ -50,7 +50,7 @@ public DruidInternalDynamicConfigResource(BrokerViewOfCoordinatorConfig brokerVi @Path("/coordinator") public Response getDynamicConfig() { - return Response.ok(brokerViewOfCoordinatorConfig.getDynamicConfiguration()).build(); + return Response.ok(brokerViewOfCoordinatorConfig.getDynamicConfig()).build(); } @POST diff --git a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java index 55a987eb43d6..5983209fdf63 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/CloneStatusManager.java @@ -19,7 +19,6 @@ package org.apache.druid.server.coordinator; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import javax.annotation.Nullable; @@ -44,7 +43,7 @@ public CloneStatusManager() */ public List getStatusForAllServers() { - return ImmutableList.copyOf(cloneStatusSnapshot.get().values()); + return List.copyOf(cloneStatusSnapshot.get().values()); } /** diff --git a/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java b/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java index e07e9e93b8c8..bf26030b0cb9 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java @@ -30,25 +30,28 @@ public class ServerCloneStatus { private final String sourceServer; + private final String targetServer; private final State state; private final long segmentLoadsRemaining; private final long segmentDropsRemaining; - private final long bytesRemaining; + private final long bytesToLoad; @JsonCreator public ServerCloneStatus( @JsonProperty("sourceServer") String sourceServer, + @JsonProperty("targetServer") String targetServer, @JsonProperty("state") State state, @JsonProperty("segmentLoadsRemaining") long segmentLoadsRemaining, @JsonProperty("segmentDropsRemaining") long segmentDropsRemaining, - @JsonProperty("bytesRemaining") long bytesRemaining + @JsonProperty("bytesToLoad") long bytesToLoad ) { this.sourceServer = sourceServer; + this.targetServer = targetServer; this.state = state; this.segmentLoadsRemaining = segmentLoadsRemaining; this.segmentDropsRemaining = segmentDropsRemaining; - this.bytesRemaining = bytesRemaining; + this.bytesToLoad = bytesToLoad; } @JsonProperty @@ -57,6 +60,12 @@ public String getSourceServer() return sourceServer; } + @JsonProperty + public String getTargetServer() + { + return targetServer; + } + @JsonProperty public long getSegmentLoadsRemaining() { @@ -70,9 +79,9 @@ public long getSegmentDropsRemaining() } @JsonProperty - public long getBytesRemaining() + public long getBytesToLoad() { - return bytesRemaining; + return bytesToLoad; } @JsonProperty @@ -81,9 +90,9 @@ public State getState() return state; } - public static ServerCloneStatus unknown(String sourceServer) + public static ServerCloneStatus unknown(String sourceServer, String targetServer) { - return new ServerCloneStatus(sourceServer, State.TARGET_SERVER_MISSING, 0, 0, 0); + return new ServerCloneStatus(sourceServer, targetServer, State.TARGET_SERVER_MISSING, 0, 0, 0); } @Override @@ -98,26 +107,35 @@ public boolean equals(Object o) ServerCloneStatus that = (ServerCloneStatus) o; return segmentLoadsRemaining == that.segmentLoadsRemaining && segmentDropsRemaining == that.segmentDropsRemaining - && bytesRemaining == that.bytesRemaining + && bytesToLoad == that.bytesToLoad && Objects.equals(sourceServer, that.sourceServer) + && Objects.equals(targetServer, that.targetServer) && state == that.state; } @Override public int hashCode() { - return Objects.hash(sourceServer, state, segmentLoadsRemaining, segmentDropsRemaining, bytesRemaining); + return Objects.hash( + sourceServer, + targetServer, + state, + segmentLoadsRemaining, + segmentDropsRemaining, + bytesToLoad + ); } @Override public String toString() { - return "CloneStatusMetrics{" + + return "ServerCloneStatus{" + "sourceServer='" + sourceServer + '\'' + + ", targetServer='" + targetServer + '\'' + ", state=" + state + ", segmentLoadsRemaining=" + segmentLoadsRemaining + ", segmentDropsRemaining=" + segmentDropsRemaining + - ", bytesRemaining=" + bytesRemaining + + ", bytesToLoad=" + bytesToLoad + '}'; } @@ -138,6 +156,6 @@ public enum State /** * Segments are loaded or being loaded. The counts give a better view of the progress. */ - LOADING + IN_PROGRESS } } diff --git a/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java b/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java index ef1daa8fac2c..4505e9dda0d0 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java @@ -147,14 +147,14 @@ public Map createCurrentStatusMap( ServerCloneStatus newStatus; if (targetServer == null) { - newStatus = ServerCloneStatus.unknown(sourceServerName); + newStatus = ServerCloneStatus.unknown(sourceServerName, targetServerName); } else { ServerCloneStatus.State state; if (!historicalMap.containsKey(sourceServerName)) { state = ServerCloneStatus.State.SOURCE_SERVER_MISSING; } else { - state = ServerCloneStatus.State.LOADING; + state = ServerCloneStatus.State.IN_PROGRESS; } for (Map.Entry queuedSegment : targetServer.getQueuedSegments().entrySet()) { @@ -165,7 +165,7 @@ public Map createCurrentStatusMap( segmentDrop += 1; } } - newStatus = new ServerCloneStatus(sourceServerName, state, segmentLoad, segmentDrop, bytesLeft); + newStatus = new ServerCloneStatus(sourceServerName, targetServerName, state, segmentLoad, segmentDrop, bytesLeft); } newStatusMap.put(targetServerName, newStatus); } diff --git a/server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java b/server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java index fa1ab90a34bc..b1b2abdacb7e 100644 --- a/server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java +++ b/server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java @@ -27,18 +27,18 @@ public class ConfigSyncStatus { - private final Set inSyncBrokers; + private final Set syncedBrokers; @JsonCreator - public ConfigSyncStatus(@JsonProperty("inSyncBrokers") Set inSyncBrokers) + public ConfigSyncStatus(@JsonProperty("syncedBrokers") Set syncedBrokers) { - this.inSyncBrokers = inSyncBrokers; + this.syncedBrokers = syncedBrokers; } @JsonProperty - public Set getInSyncBrokers() + public Set getSyncedBrokers() { - return inSyncBrokers; + return syncedBrokers; } @Override @@ -51,20 +51,20 @@ public boolean equals(Object o) return false; } ConfigSyncStatus that = (ConfigSyncStatus) o; - return Objects.equals(inSyncBrokers, that.inSyncBrokers); + return Objects.equals(syncedBrokers, that.syncedBrokers); } @Override public int hashCode() { - return Objects.hashCode(inSyncBrokers); + return Objects.hashCode(syncedBrokers); } @Override public String toString() { return "ConfigSyncStatus{" + - "inSyncBrokers=" + inSyncBrokers + + "syncedBrokers=" + syncedBrokers + '}'; } } diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java index 8f5fc5d5b3ec..4a5fe46ec594 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java @@ -130,7 +130,7 @@ private void pushConfigToBroker(ServiceLocation brokerLocation) try { CoordinatorDynamicConfig currentDynamicConfig = configManager.getCurrentDynamicConfig(); - boolean success = brokerClient.updateDynamicConfig(currentDynamicConfig).get(); + boolean success = brokerClient.updateCoordinatorDynamicConfig(currentDynamicConfig).get(); if (success) { markBrokerAsSynced(currentDynamicConfig, brokerLocation); } diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java index d42969094406..2d921d1175df 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java @@ -165,8 +165,7 @@ public Response getCloneStatus(@QueryParam("targetServer") @Nullable String targ ServerCloneStatus statusForServer = cloneStatusManager.getStatusForServer(targetServer); return Response.ok(ImmutableMap.of(targetServer, statusForServer)).build(); } else { - // TODO: this or make a class? - List statusForAllServers = cloneStatusManager.getStatusForAllServers(); + final List statusForAllServers = cloneStatusManager.getStatusForAllServers(); return Response.ok(Map.of("cloneStatus", statusForAllServers)).build(); } } diff --git a/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java b/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java index d0665f600973..ec310d592226 100644 --- a/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java +++ b/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java @@ -133,7 +133,7 @@ public void testSingleServerAddedRemovedSegment() throws Exception ServerSelector selector = (actualPartitionHolder.iterator().next()).getObject(); Assert.assertFalse(selector.isEmpty()); Assert.assertEquals(segment, selector.getSegment()); - Assert.assertEquals(druidServer, selector.pick(null, CloneQueryMode.EXCLUDE).getServer()); + Assert.assertEquals(druidServer, selector.pick(null, CloneQueryMode.EXCLUDE_CLONES).getServer()); Assert.assertNotNull(timeline.findChunk(intervals, "v1", partition)); unannounceSegmentForServer(druidServer, segment, zkPathsConfig); @@ -392,9 +392,9 @@ public void testMultipleTiers() throws Exception // Verify that the ServerSelector always picks Tier 1 for (int i = 0; i < 5; ++i) { - Assert.assertEquals(server21, selector.pick(null, CloneQueryMode.EXCLUDE).getServer()); + Assert.assertEquals(server21, selector.pick(null, CloneQueryMode.EXCLUDE_CLONES).getServer()); } - Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDE_CLONES)); } @Test @@ -452,9 +452,9 @@ public void testRealtimeTasksNotWatched() throws Exception // Verify that the ServerSelector always picks the Historical server for (int i = 0; i < 5; ++i) { - Assert.assertEquals(historicalServer, selector.pick(null, CloneQueryMode.EXCLUDE).getServer()); + Assert.assertEquals(historicalServer, selector.pick(null, CloneQueryMode.EXCLUDE_CLONES).getServer()); } - Assert.assertEquals(Collections.singletonList(historicalServer.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(Collections.singletonList(historicalServer.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDE_CLONES)); } @Test @@ -514,9 +514,9 @@ public void testIgnoredTiers() throws Exception // Verify that the ServerSelector always picks Tier 1 for (int i = 0; i < 5; ++i) { - Assert.assertEquals(server21, selector.pick(null, CloneQueryMode.EXCLUDE).getServer()); + Assert.assertEquals(server21, selector.pick(null, CloneQueryMode.EXCLUDE_CLONES).getServer()); } - Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDE_CLONES)); } @Test(expected = ISE.class) @@ -596,7 +596,7 @@ private void assertValues( ServerSelector selector = ((SingleElementPartitionChunk) actualPartitionHolder.iterator() .next()).getObject(); Assert.assertFalse(selector.isEmpty()); - Assert.assertEquals(expectedPair.rhs.rhs.lhs, selector.pick(null, CloneQueryMode.EXCLUDE).getServer()); + Assert.assertEquals(expectedPair.rhs.rhs.lhs, selector.pick(null, CloneQueryMode.EXCLUDE_CLONES).getServer()); Assert.assertEquals(expectedPair.rhs.rhs.rhs, selector.getSegment()); } } diff --git a/server/src/test/java/org/apache/druid/client/BrokerViewOfCoordinatorConfigTest.java b/server/src/test/java/org/apache/druid/client/BrokerViewOfCoordinatorConfigTest.java index e8dfadb7261f..5a014531bf54 100644 --- a/server/src/test/java/org/apache/druid/client/BrokerViewOfCoordinatorConfigTest.java +++ b/server/src/test/java/org/apache/druid/client/BrokerViewOfCoordinatorConfigTest.java @@ -53,6 +53,6 @@ public void testFetchesConfigOnStartup() { target.start(); Mockito.verify(coordinatorClient, Mockito.times(1)).getCoordinatorDynamicConfig(); - Assert.assertEquals(config, target.getDynamicConfiguration()); + Assert.assertEquals(config, target.getDynamicConfig()); } } diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java index e4660e0ede1b..76846935f940 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java @@ -87,7 +87,7 @@ public void testComputeEtag_nonHistorical() makeHistoricalServerSelector(0), makeRealtimeServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); + String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, QUERY_CACHE_KEY); Assert.assertNull(actual); } @@ -100,14 +100,14 @@ public void testComputeEtag_DifferentHistoricals() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, QUERY_CACHE_KEY); Assert.assertNotNull(actual1); selectors = ImmutableSet.of( makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, QUERY_CACHE_KEY); Assert.assertNotNull(actual2); Assert.assertEquals("cache key should not change for same server selectors", actual1, actual2); @@ -115,7 +115,7 @@ public void testComputeEtag_DifferentHistoricals() makeHistoricalServerSelector(2), makeHistoricalServerSelector(1) ); - String actual3 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, QUERY_CACHE_KEY); + String actual3 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, QUERY_CACHE_KEY); Assert.assertNotNull(actual3); Assert.assertNotEquals(actual1, actual3); } @@ -129,10 +129,10 @@ public void testComputeEtag_DifferentQueryCacheKey() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, new byte[]{1, 2}); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, new byte[]{1, 2}); Assert.assertNotNull(actual1); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, new byte[]{3, 4}); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, new byte[]{3, 4}); Assert.assertNotNull(actual2); Assert.assertNotEquals(actual1, actual2); } @@ -147,14 +147,14 @@ public void testComputeEtag_nonJoinDataSource() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, FULL_QUERY_CACHE_KEY); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, FULL_QUERY_CACHE_KEY); Assert.assertNotNull(actual1); selectors = ImmutableSet.of( makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, null); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, null); Assert.assertNotNull(actual2); Assert.assertEquals(actual1, actual2); } @@ -170,7 +170,7 @@ public void testComputeEtag_joinWithUnsupportedCaching() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, null); Assert.assertNull(actual); } @@ -188,7 +188,7 @@ public void testComputeEtag_noEffectifBySegment() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, null); Assert.assertNotNull(actual); } @@ -207,7 +207,7 @@ public void testComputeEtag_noEffectIfUseAndPopulateFalse() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, null); Assert.assertNotNull(actual); } @@ -304,7 +304,7 @@ private SegmentServerSelector makeServerSelector(boolean isHistorical, int parti 0 ); expect(server.isSegmentReplicationTarget()).andReturn(isHistorical).anyTimes(); - expect(serverSelector.pick(query, CloneQueryMode.EXCLUDE)).andReturn(queryableDruidServer).anyTimes(); + expect(serverSelector.pick(query, CloneQueryMode.EXCLUDE_CLONES)).andReturn(queryableDruidServer).anyTimes(); expect(queryableDruidServer.getServer()).andReturn(server).anyTimes(); expect(serverSelector.getSegment()).andReturn(segment).anyTimes(); replay(serverSelector, queryableDruidServer, server); diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java index ae4c4e8a5ab5..20972a6127a9 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientFunctionalityTest.java @@ -46,7 +46,6 @@ import org.apache.druid.query.context.ResponseContext; import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.coordination.ServerType; -import org.apache.druid.server.coordination.TestCoordinatorClient; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.apache.druid.timeline.DataSegment; import org.apache.druid.timeline.TimelineLookup; diff --git a/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java b/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java index e8ac181178ca..1ebba1736924 100644 --- a/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java +++ b/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java @@ -248,7 +248,7 @@ public void testRun() throws Exception Assert.assertEquals(2, client2.getNumOpenConnections()); - Assert.assertEquals(serverSelector.pick(null, CloneQueryMode.EXCLUDE), queryableDruidServer2); + Assert.assertEquals(serverSelector.pick(null, CloneQueryMode.EXCLUDE_CLONES), queryableDruidServer2); EasyMock.verify(httpClient); } diff --git a/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java b/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java index df8b6fd42cca..dfc3a49dfbd0 100644 --- a/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java +++ b/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java @@ -51,7 +51,7 @@ public void testDifferentConnectionCount() ServerSelector serverSelector = initSelector(s1, s2, s3); for (int i = 0; i < 100; ++i) { - Assert.assertEquals(s2, serverSelector.pick(null, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(s2, serverSelector.pick(null, CloneQueryMode.EXCLUDE_CLONES)); } } @@ -64,7 +64,7 @@ public void testBalancerTieBreaking() Set pickedServers = new HashSet<>(); for (int i = 0; i < 100; ++i) { - pickedServers.add(serverSelector.pick(null, CloneQueryMode.EXCLUDE).getServer().getName()); + pickedServers.add(serverSelector.pick(null, CloneQueryMode.EXCLUDE_CLONES).getServer().getName()); } Assert.assertTrue( "Multiple servers should be selected when the number of connections is equal.", diff --git a/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java b/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java index 765752cfd43a..8aac8184104a 100644 --- a/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java +++ b/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java @@ -242,10 +242,10 @@ private void testTierSelectorStrategy( serverSelector.addServerAndUpdateSegment(server, serverSelector.getSegment()); } - Assert.assertEquals(expectedSelection[0], serverSelector.pick(null, CloneQueryMode.EXCLUDE)); - Assert.assertEquals(expectedSelection[0], serverSelector.pick(EasyMock.createMock(Query.class), CloneQueryMode.EXCLUDE)); - Assert.assertEquals(expectedCandidates, serverSelector.getCandidates(-1, CloneQueryMode.EXCLUDE)); - Assert.assertEquals(expectedCandidates.subList(0, 2), serverSelector.getCandidates(2, CloneQueryMode.EXCLUDE)); + Assert.assertEquals(expectedSelection[0], serverSelector.pick(null, CloneQueryMode.EXCLUDE_CLONES)); + Assert.assertEquals(expectedSelection[0], serverSelector.pick(EasyMock.createMock(Query.class), CloneQueryMode.EXCLUDE_CLONES)); + Assert.assertEquals(expectedCandidates, serverSelector.getCandidates(-1, CloneQueryMode.EXCLUDE_CLONES)); + Assert.assertEquals(expectedCandidates.subList(0, 2), serverSelector.getCandidates(2, CloneQueryMode.EXCLUDE_CLONES)); } @Test diff --git a/server/src/test/java/org/apache/druid/server/coordinator/ServerCloneStatusTest.java b/server/src/test/java/org/apache/druid/server/coordinator/ServerCloneStatusTest.java index 0bb299e0bec8..f5870cdca71f 100644 --- a/server/src/test/java/org/apache/druid/server/coordinator/ServerCloneStatusTest.java +++ b/server/src/test/java/org/apache/druid/server/coordinator/ServerCloneStatusTest.java @@ -29,7 +29,7 @@ public class ServerCloneStatusTest @Test public void testSerde() throws Exception { - ServerCloneStatus metrics = new ServerCloneStatus("host2", ServerCloneStatus.State.LOADING, 3012, 10, 100); + ServerCloneStatus metrics = new ServerCloneStatus("host2", "host1", ServerCloneStatus.State.IN_PROGRESS, 3012, 10, 100); byte[] bytes = DefaultObjectMapper.INSTANCE.writeValueAsBytes(metrics); ServerCloneStatus deserialized = DefaultObjectMapper.INSTANCE.readValue(bytes, ServerCloneStatus.class); Assert.assertEquals(deserialized, metrics); diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java index 3f58adee0cbd..ef9925dd329c 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java @@ -87,12 +87,12 @@ public void testGetBrokerStatus() public void testGetCloneStatus() { List statusMetrics = ImmutableList.of( - new ServerCloneStatus("hist3", ServerCloneStatus.State.LOADING, 2, 0, 1000), - ServerCloneStatus.unknown("hist4") + new ServerCloneStatus("hist3", "hist1", ServerCloneStatus.State.IN_PROGRESS, 2, 0, 1000), + ServerCloneStatus.unknown("hist4", "hist3") ); EasyMock.expect(cloneStatusManager.getStatusForAllServers()).andReturn(statusMetrics).once(); - EasyMock.expect(cloneStatusManager.getStatusForServer("hist2")).andReturn(ServerCloneStatus.unknown("hist4")).once(); + EasyMock.expect(cloneStatusManager.getStatusForServer("hist2")).andReturn(ServerCloneStatus.unknown("hist4", "hist3")).once(); EasyMock.replay(coordinatorDynamicConfigSyncer); EasyMock.replay(cloneStatusManager); @@ -106,8 +106,8 @@ public void testGetCloneStatus() Assert.assertEquals(200, response.getStatus()); Assert.assertEquals(statusMetrics, response.getEntity()); - response = resource.getCloneStatus("hist2"); + response = resource.getCloneStatus("hist2"); //TODO: fix Assert.assertEquals(200, response.getStatus()); - Assert.assertEquals(Map.of("hist2", ServerCloneStatus.unknown("hist4")), response.getEntity()); + Assert.assertEquals(Map.of("hist2", ServerCloneStatus.unknown("hist4", "hist3")), response.getEntity()); } } diff --git a/services/src/main/java/org/apache/druid/cli/CliBroker.java b/services/src/main/java/org/apache/druid/cli/CliBroker.java index 21c4e933ba4b..e1b36f88dd48 100644 --- a/services/src/main/java/org/apache/druid/cli/CliBroker.java +++ b/services/src/main/java/org/apache/druid/cli/CliBroker.java @@ -61,7 +61,7 @@ import org.apache.druid.server.BrokerQueryResource; import org.apache.druid.server.ClientInfoResource; import org.apache.druid.server.ClientQuerySegmentWalker; -import org.apache.druid.server.DruidInternalDynamicConfigResource; +import org.apache.druid.server.BrokerDynamicConfigResource; import org.apache.druid.server.ResponseContextConfig; import org.apache.druid.server.SegmentManager; import org.apache.druid.server.SubqueryGuardrailHelper; @@ -162,7 +162,7 @@ protected List getModules() binder.bind(SubqueryCountStatsProvider.class).toInstance(new SubqueryCountStatsProvider()); Jerseys.addResource(binder, BrokerResource.class); Jerseys.addResource(binder, ClientInfoResource.class); - Jerseys.addResource(binder, DruidInternalDynamicConfigResource.class); + Jerseys.addResource(binder, BrokerDynamicConfigResource.class); LifecycleModule.register(binder, BrokerQueryResource.class); From f475cf6535b24af964fb50e7ad157660785d507c Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Sun, 27 Apr 2025 17:34:12 +0530 Subject: [PATCH 32/38] Refactor to address comments --- .../client/BrokerViewOfCoordinatorConfig.java | 15 ++-- .../apache/druid/client/ServerViewUtil.java | 5 +- .../client/selector/HistoricalFilter.java | 9 +++ .../server/BrokerDynamicConfigResource.java | 9 +++ .../druid/server/BrokerQueryResource.java | 7 +- .../druid/server/ClientInfoResource.java | 6 +- .../druid/server/http/BrokerSyncStatus.java | 3 + .../druid/server/http/ConfigSyncStatus.java | 70 ------------------- .../http/CoordinatorDynamicConfigSyncer.java | 4 +- .../CoordinatorDynamicConfigsResource.java | 50 +++++++++++-- .../druid/server/ClientInfoResourceTest.java | 1 - ...CoordinatorDynamicConfigsResourceTest.java | 12 ++-- 12 files changed, 84 insertions(+), 107 deletions(-) delete mode 100644 server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java diff --git a/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java index 79da551078e5..d73f7d92dd59 100644 --- a/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java +++ b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java @@ -50,9 +50,9 @@ public class BrokerViewOfCoordinatorConfig implements HistoricalFilter @GuardedBy("this") private CoordinatorDynamicConfig config; @GuardedBy("this") - private Set cloneServers; + private Set targetCloneServers; @GuardedBy("this") - private Set serversBeingCloned; + private Set sourceCloneServers; @Inject public BrokerViewOfCoordinatorConfig(CoordinatorClient coordinatorClient) @@ -73,8 +73,8 @@ public synchronized void setDynamicConfig(@NotNull CoordinatorDynamicConfig upda { config = updatedConfig; final Map cloneServers = config.getCloneServers(); - this.cloneServers = ImmutableSet.copyOf(cloneServers.keySet()); - this.serversBeingCloned = ImmutableSet.copyOf(cloneServers.values()); + this.targetCloneServers = ImmutableSet.copyOf(cloneServers.keySet()); + this.sourceCloneServers = ImmutableSet.copyOf(cloneServers.values()); } @LifecycleStart @@ -90,7 +90,6 @@ public void start() } catch (Exception e) { // If the fetch fails, the broker should not serve queries. Throw the exception and try again on restart. - log.error(e, "Failed to initialize coordinator dynamic config"); throw new RuntimeException("Failed to initialize coordinator dynamic config", e); } } @@ -125,15 +124,15 @@ private synchronized Set getCurrentServersToIgnore(CloneQueryMode cloneQ switch (cloneQueryMode) { case PREFER_CLONES: // Remove servers being cloned targets, so that clones are queried. - return serversBeingCloned; + return sourceCloneServers; case EXCLUDE_CLONES: // Remove clones, so that only source servers are queried. - return cloneServers; + return targetCloneServers; case INCLUDE_CLONES: // Don't remove either return ImmutableSet.of(); default: - throw DruidException.defensive("Unexpected value: " + cloneQueryMode); + throw DruidException.defensive("Unexpected value: [%s]", cloneQueryMode); } } } diff --git a/server/src/main/java/org/apache/druid/client/ServerViewUtil.java b/server/src/main/java/org/apache/druid/client/ServerViewUtil.java index 234ef84328a1..6369833000b5 100644 --- a/server/src/main/java/org/apache/druid/client/ServerViewUtil.java +++ b/server/src/main/java/org/apache/druid/client/ServerViewUtil.java @@ -19,7 +19,6 @@ package org.apache.druid.client; -import org.apache.druid.client.selector.HistoricalFilter; import org.apache.druid.client.selector.ServerSelector; import org.apache.druid.query.CloneQueryMode; import org.apache.druid.query.LocatedSegmentDescriptor; @@ -45,11 +44,10 @@ public static List getTargetLocations( String datasource, List intervals, int numCandidates, - HistoricalFilter historicalFilter, CloneQueryMode cloneQueryMode ) { - return getTargetLocations(serverView, new TableDataSource(datasource), intervals, numCandidates, historicalFilter, cloneQueryMode); + return getTargetLocations(serverView, new TableDataSource(datasource), intervals, numCandidates, cloneQueryMode); } public static List getTargetLocations( @@ -57,7 +55,6 @@ public static List getTargetLocations( TableDataSource datasource, List intervals, int numCandidates, - HistoricalFilter historicalFilter, CloneQueryMode cloneQueryMode ) { diff --git a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java index f41c8c80e89e..85454e6e1ddc 100644 --- a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java +++ b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java @@ -25,10 +25,19 @@ import java.util.Set; +/** + * Interface that denotes some sort of filtering on the historcals, based on {@link CloneQueryMode}. + */ public interface HistoricalFilter { + /** + * Perform no filtering, regardless of the query mode. + */ HistoricalFilter IDENTITY_FILTER = (historicalServers, mode) -> historicalServers; + /** + * Perform a filtering on the historicalServers paramter, based on the cloneQueryMode paramter. + */ Int2ObjectRBTreeMap> getQueryableServers( Int2ObjectRBTreeMap> historicalServers, CloneQueryMode mode diff --git a/server/src/main/java/org/apache/druid/server/BrokerDynamicConfigResource.java b/server/src/main/java/org/apache/druid/server/BrokerDynamicConfigResource.java index 82dba394fee3..e29692fb993a 100644 --- a/server/src/main/java/org/apache/druid/server/BrokerDynamicConfigResource.java +++ b/server/src/main/java/org/apache/druid/server/BrokerDynamicConfigResource.java @@ -33,6 +33,9 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +/** + * Resource for fetching and updating the {@link CoordinatorDynamicConfig} on the Broker. + */ @Path("/druid-internal/v1/config") public class BrokerDynamicConfigResource { @@ -44,6 +47,9 @@ public BrokerDynamicConfigResource(BrokerViewOfCoordinatorConfig brokerViewOfCoo this.brokerViewOfCoordinatorConfig = brokerViewOfCoordinatorConfig; } + /** + * Returns the Broker's view of the {@link CoordinatorDynamicConfig}. + */ @GET @Produces(MediaType.APPLICATION_JSON) @ResourceFilters(ConfigResourceFilter.class) @@ -53,6 +59,9 @@ public Response getDynamicConfig() return Response.ok(brokerViewOfCoordinatorConfig.getDynamicConfig()).build(); } + /** + * Updates the {@link BrokerViewOfCoordinatorConfig} with the dynamicConfig paramter. + */ @POST @Consumes(MediaType.APPLICATION_JSON) @ResourceFilters(ConfigResourceFilter.class) diff --git a/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java b/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java index 58fe86e0f919..9144d3f903dd 100644 --- a/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java +++ b/server/src/main/java/org/apache/druid/server/BrokerQueryResource.java @@ -23,7 +23,6 @@ import com.fasterxml.jackson.jaxrs.smile.SmileMediaTypes; import com.google.inject.Inject; import com.sun.jersey.spi.container.ResourceFilters; -import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.ServerViewUtil; import org.apache.druid.client.TimelineServerView; import org.apache.druid.guice.annotations.Json; @@ -57,7 +56,6 @@ public class BrokerQueryResource extends QueryResource { private final TimelineServerView brokerServerView; - private final BrokerViewOfCoordinatorConfig configView; @Inject public BrokerQueryResource( @@ -69,8 +67,7 @@ public BrokerQueryResource( AuthorizerMapper authorizerMapper, ResponseContextConfig responseContextConfig, @Self DruidNode selfNode, - TimelineServerView brokerServerView, - BrokerViewOfCoordinatorConfig configView + TimelineServerView brokerServerView ) { super( @@ -84,7 +81,6 @@ public BrokerQueryResource( selfNode ); this.brokerServerView = brokerServerView; - this.configView = configView; } @POST @@ -116,7 +112,6 @@ public Response getQueryTargets( ev.getBaseTableDataSource(), ev.getEffectiveQuerySegmentSpec().getIntervals(), numCandidates, - configView, cloneQueryMode ) ); diff --git a/server/src/main/java/org/apache/druid/server/ClientInfoResource.java b/server/src/main/java/org/apache/druid/server/ClientInfoResource.java index 09a8c81b78ac..9e38aa3ab8a6 100644 --- a/server/src/main/java/org/apache/druid/server/ClientInfoResource.java +++ b/server/src/main/java/org/apache/druid/server/ClientInfoResource.java @@ -25,7 +25,6 @@ import com.google.common.collect.Maps; import com.google.inject.Inject; import com.sun.jersey.spi.container.ResourceFilters; -import org.apache.druid.client.BrokerViewOfCoordinatorConfig; import org.apache.druid.client.DruidDataSource; import org.apache.druid.client.FilteredServerInventoryView; import org.apache.druid.client.ServerViewUtil; @@ -90,13 +89,11 @@ public class ClientInfoResource private SegmentMetadataQueryConfig segmentMetadataQueryConfig; private final AuthConfig authConfig; private final AuthorizerMapper authorizerMapper; - private final BrokerViewOfCoordinatorConfig configView; @Inject public ClientInfoResource( FilteredServerInventoryView serverInventoryView, TimelineServerView timelineServerView, - BrokerViewOfCoordinatorConfig configView, SegmentMetadataQueryConfig segmentMetadataQueryConfig, AuthConfig authConfig, AuthorizerMapper authorizerMapper @@ -108,7 +105,6 @@ public ClientInfoResource( new SegmentMetadataQueryConfig() : segmentMetadataQueryConfig; this.authConfig = authConfig; this.authorizerMapper = authorizerMapper; - this.configView = configView; } @GET @@ -322,7 +318,7 @@ public Iterable getQueryTargets( intervalList.add(Intervals.of(interval.trim())); } List condensed = JodaUtils.condenseIntervals(intervalList); - return ServerViewUtil.getTargetLocations(timelineServerView, datasource, condensed, numCandidates, configView, cloneQueryMode); + return ServerViewUtil.getTargetLocations(timelineServerView, datasource, condensed, numCandidates, cloneQueryMode); } protected DateTime getCurrentTime() diff --git a/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java b/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java index 04ac4e8bae8a..483be1db5bd4 100644 --- a/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java +++ b/server/src/main/java/org/apache/druid/server/http/BrokerSyncStatus.java @@ -25,6 +25,9 @@ import java.util.Objects; +/** + * Immutable class which represents the status of a dynamic configuration sync with a specific broker. + */ public class BrokerSyncStatus { private final String host; diff --git a/server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java b/server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java deleted file mode 100644 index b1b2abdacb7e..000000000000 --- a/server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java +++ /dev/null @@ -1,70 +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.server.http; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.Objects; -import java.util.Set; - -public class ConfigSyncStatus -{ - private final Set syncedBrokers; - - @JsonCreator - public ConfigSyncStatus(@JsonProperty("syncedBrokers") Set syncedBrokers) - { - this.syncedBrokers = syncedBrokers; - } - - @JsonProperty - public Set getSyncedBrokers() - { - return syncedBrokers; - } - - @Override - public boolean equals(Object o) - { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ConfigSyncStatus that = (ConfigSyncStatus) o; - return Objects.equals(syncedBrokers, that.syncedBrokers); - } - - @Override - public int hashCode() - { - return Objects.hashCode(syncedBrokers); - } - - @Override - public String toString() - { - return "ConfigSyncStatus{" + - "syncedBrokers=" + syncedBrokers + - '}'; - } -} diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java index 4a5fe46ec594..a86249ce0a72 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java @@ -93,9 +93,9 @@ public void broadcastConfigToBrokers() } } - public synchronized ConfigSyncStatus getInSyncBrokers() + public synchronized Set getInSyncBrokers() { - return new ConfigSyncStatus(Set.copyOf(inSyncBrokers)); + return Set.copyOf(inSyncBrokers); } public void onLeaderStart() diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java index 2d921d1175df..58fb9a221596 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java @@ -19,6 +19,8 @@ package org.apache.druid.server.http; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.ImmutableMap; import com.sun.jersey.spi.container.ResourceFilters; import org.apache.druid.audit.AuditManager; @@ -46,7 +48,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.util.List; -import java.util.Map; +import java.util.Set; /** */ @@ -162,11 +164,51 @@ public Response getBrokerStatus() public Response getCloneStatus(@QueryParam("targetServer") @Nullable String targetServer) { if (targetServer != null) { - ServerCloneStatus statusForServer = cloneStatusManager.getStatusForServer(targetServer); + final ServerCloneStatus statusForServer = cloneStatusManager.getStatusForServer(targetServer); return Response.ok(ImmutableMap.of(targetServer, statusForServer)).build(); } else { - final List statusForAllServers = cloneStatusManager.getStatusForAllServers(); - return Response.ok(Map.of("cloneStatus", statusForAllServers)).build(); + final CloneStatus statusForAllServers = new CloneStatus(cloneStatusManager.getStatusForAllServers()); + return Response.ok(statusForAllServers).build(); + } + } + + /** + * Contains the current set of Brokers which have been synced with the latest {@link CoordinatorDynamicConfig}. + */ + public static class ConfigSyncStatus + { + private final Set syncedBrokers; + + @JsonCreator + public ConfigSyncStatus(@JsonProperty("syncedBrokers") Set syncedBrokers) + { + this.syncedBrokers = syncedBrokers; + } + + @JsonProperty + public Set getSyncedBrokers() + { + return syncedBrokers; + } + } + + /** + * Contains the current set of Brokers which have been synced with the latest {@link CoordinatorDynamicConfig}. + */ + public static class CloneStatus + { + private final List cloneStatus; + + @JsonCreator + public CloneStatus(@JsonProperty("cloneStatus") List cloneStatus) + { + this.cloneStatus = cloneStatus; + } + + @JsonProperty + public List getCloneStatus() + { + return cloneStatus; } } } diff --git a/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java b/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java index ca8e238a2220..8e9f0c54c12c 100644 --- a/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/ClientInfoResourceTest.java @@ -406,7 +406,6 @@ private ClientInfoResource getResourceTestHelper( return new ClientInfoResource( serverInventoryView, timelineServerView, - null, segmentMetadataQueryConfig, new AuthConfig(), null diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java index ef9925dd329c..6e95e675e28e 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java @@ -55,12 +55,10 @@ public void testGetBrokerStatus() { EasyMock.expect(coordinatorDynamicConfigSyncer.getInSyncBrokers()) .andReturn( - new ConfigSyncStatus( - ImmutableSet.of( - new BrokerSyncStatus("host1", 8080, 1000 - ) - ) - ) + ImmutableSet.of( + new BrokerSyncStatus("host1", 8080, 1000 + ) + ) ) .once(); EasyMock.replay(coordinatorDynamicConfigSyncer); @@ -75,7 +73,7 @@ public void testGetBrokerStatus() Assert.assertEquals(200, response.getStatus()); - ConfigSyncStatus expected = new ConfigSyncStatus( + CoordinatorDynamicConfigsResource.ConfigSyncStatus expected = new CoordinatorDynamicConfigsResource.ConfigSyncStatus( ImmutableSet.of( new BrokerSyncStatus("host1", 8080, 1000) ) From cdda2e2d7f75486eb4df70ae55c9e35094f932a9 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Sun, 27 Apr 2025 17:50:39 +0530 Subject: [PATCH 33/38] Update docs --- docs/api-reference/service-status-api.md | 19 +++--- .../http/CoordinatorDynamicConfigSyncer.java | 52 ++++++++++++---- .../CoordinatorDynamicConfigsResource.java | 59 ++++++++++++++++++- ...CoordinatorDynamicConfigsResourceTest.java | 4 +- .../java/org/apache/druid/cli/CliBroker.java | 2 +- 5 files changed, 112 insertions(+), 24 deletions(-) diff --git a/docs/api-reference/service-status-api.md b/docs/api-reference/service-status-api.md index 70761de262ef..48679658d440 100644 --- a/docs/api-reference/service-status-api.md +++ b/docs/api-reference/service-status-api.md @@ -711,13 +711,16 @@ Host: http://COORDINATOR_IP:COORDINATOR_PORT ```json { - "localhost:8083": { - "sourceServer": "localhost:8089", - "state": "LOADING", - "segmentLoadsRemaining": 0, - "segmentDropsRemaining": 0, - "bytesRemaining": 0 + "cloneStatus": [ + { + "sourceServer": "localhost:8089", + "targetServer": "localhost:8083", + "state": "IN_PROGRESS", + "segmentLoadsRemaining": 0, + "segmentDropsRemaining": 0, + "bytesToLoad": 0 } + ] } ``` @@ -775,11 +778,11 @@ Host: http://COORDINATOR_IP:COORDINATOR_PORT ```json { - "inSyncBrokers": [ + "syncedBrokers": [ { "host": "localhost", "port": 8082, - "syncTimeInMs": 1745298963900 + "syncTimeInMs": 1745756337472 } ] } diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java index a86249ce0a72..cdf4611a365d 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigSyncer.java @@ -20,6 +20,7 @@ package org.apache.druid.server.http; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.errorprone.annotations.concurrent.GuardedBy; import com.google.inject.Inject; import org.apache.druid.client.broker.BrokerClient; import org.apache.druid.client.broker.BrokerClientImpl; @@ -58,12 +59,14 @@ public class CoordinatorDynamicConfigSyncer private final ObjectMapper jsonMapper; private final DruidNodeDiscoveryProvider druidNodeDiscovery; - private final AtomicReference lastKnownConfig = new AtomicReference<>(); private final ServiceClientFactory clientFactory; - private final Set inSyncBrokers; private final ScheduledExecutorService exec; private @Nullable Future syncFuture = null; + @GuardedBy("this") + private final Set inSyncBrokers; + private final AtomicReference lastKnownConfig = new AtomicReference<>(); + @Inject public CoordinatorDynamicConfigSyncer( @EscalatedGlobal final ServiceClientFactory clientFactory, @@ -80,12 +83,19 @@ public CoordinatorDynamicConfigSyncer( this.inSyncBrokers = ConcurrentHashMap.newKeySet(); } - public void triggerBroadcastConfigToBrokers() + /** + * Queues the configuration sync to the brokers without blocking the calling thread. + */ + public void queueBroadcastConfigToBrokers() { exec.submit(this::broadcastConfigToBrokers); } - public void broadcastConfigToBrokers() + /** + * Push the latest coordinator dynamic config, provided by the configManager to all currently known Brokers. Also + * invalidates the set of inSyncBrokers if the config has changed. + */ + private void broadcastConfigToBrokers() { invalidateInSyncBrokersIfNeeded(); for (ServiceLocation broker : getKnownBrokers()) { @@ -93,11 +103,17 @@ public void broadcastConfigToBrokers() } } + /** + * Returns the set of Brokers which have been updated with the latest {@link CoordinatorDynamicConfig}. + */ public synchronized Set getInSyncBrokers() { return Set.copyOf(inSyncBrokers); } + /** + * Schedules a periodic sync with brokers when the coordinator becomes the leader. + */ public void onLeaderStart() { log.info("Starting coordinator config syncing to brokers on leader node."); @@ -109,6 +125,9 @@ public void onLeaderStart() ); } + /** + * Stops the sync when coordinator stops being the leader. + */ public void onLeaderStop() { log.info("Not leader, stopping coordinator config syncing to brokers."); @@ -117,6 +136,10 @@ public void onLeaderStop() } } + /** + * Push the latest coordinator dynamic config, provided by the configManager to the Broker at the brokerLocation + * param. + */ private void pushConfigToBroker(ServiceLocation brokerLocation) { final BrokerClient brokerClient = new BrokerClientImpl( @@ -137,14 +160,13 @@ private void pushConfigToBroker(ServiceLocation brokerLocation) } catch (Exception e) { // Catch and ignore the exception, wait for the next sync. - log.error( - e, - "Exception while syncing dynamic configuration to broker[%s]", - brokerLocation - ); + log.error(e, "Exception while syncing dynamic configuration to broker[%s]", brokerLocation); } } + /** + * Returns a list of {@link ServiceLocation} for all brokers currently known to the druidNodeDiscovery. + */ private Set getKnownBrokers() { return druidNodeDiscovery.getForNodeRole(NodeRole.BROKER) @@ -154,6 +176,10 @@ private Set getKnownBrokers() .collect(Collectors.toSet()); } + /** + * Clears the set of inSyncBrokers and updates the lastKnownConfig if the latest coordinator dynamic config is + * different from the config tracked by this class. + */ private synchronized void invalidateInSyncBrokersIfNeeded() { final CoordinatorDynamicConfig currentDynamicConfig = configManager.getCurrentDynamicConfig(); @@ -164,6 +190,9 @@ private synchronized void invalidateInSyncBrokersIfNeeded() } } + /** + * Adds a broker to the set of inSyncBrokers if the coordinator dynamic config has not changed. + */ private synchronized void markBrokerAsSynced(CoordinatorDynamicConfig config, ServiceLocation broker) { if (config.equals(lastKnownConfig.get())) { @@ -171,6 +200,9 @@ private synchronized void markBrokerAsSynced(CoordinatorDynamicConfig config, Se } } + /** + * Utility method to convert {@link DiscoveryDruidNode} to a {@link ServiceLocation} + */ @Nullable private static ServiceLocation convertDiscoveryNodeToServiceLocation(DiscoveryDruidNode discoveryDruidNode) { @@ -186,6 +218,4 @@ private static ServiceLocation convertDiscoveryNodeToServiceLocation(DiscoveryDr "" ); } - - } diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java index 58fb9a221596..e7523a1bab11 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java @@ -48,6 +48,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.util.List; +import java.util.Objects; import java.util.Set; /** @@ -99,7 +100,7 @@ public Response setDynamicConfigs( ); if (setResult.isOk()) { - coordinatorDynamicConfigSyncer.triggerBroadcastConfigToBrokers(); + coordinatorDynamicConfigSyncer.queueBroadcastConfigToBrokers(); return Response.ok().build(); } else { return Response.status(Response.Status.BAD_REQUEST) @@ -154,7 +155,7 @@ public Response getDatasourceRuleHistory( @Produces(MediaType.APPLICATION_JSON) public Response getBrokerStatus() { - return Response.ok(coordinatorDynamicConfigSyncer.getInSyncBrokers()).build(); + return Response.ok(new ConfigSyncStatus(coordinatorDynamicConfigSyncer.getInSyncBrokers())).build(); } @GET @@ -190,6 +191,33 @@ public Set getSyncedBrokers() { return syncedBrokers; } + + @Override + public boolean equals(Object o) + { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConfigSyncStatus that = (ConfigSyncStatus) o; + return Objects.equals(syncedBrokers, that.syncedBrokers); + } + + @Override + public int hashCode() + { + return Objects.hashCode(syncedBrokers); + } + + @Override + public String toString() + { + return "ConfigSyncStatus{" + + "syncedBrokers=" + syncedBrokers + + '}'; + } } /** @@ -210,5 +238,32 @@ public List getCloneStatus() { return cloneStatus; } + + @Override + public boolean equals(Object o) + { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CloneStatus that = (CloneStatus) o; + return Objects.equals(cloneStatus, that.cloneStatus); + } + + @Override + public int hashCode() + { + return Objects.hashCode(cloneStatus); + } + + @Override + public String toString() + { + return "CloneStatus{" + + "cloneStatus=" + cloneStatus + + '}'; + } } } diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java index 6e95e675e28e..9ec63a40509b 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java @@ -102,9 +102,9 @@ public void testGetCloneStatus() ); Response response = resource.getCloneStatus(null); Assert.assertEquals(200, response.getStatus()); - Assert.assertEquals(statusMetrics, response.getEntity()); + Assert.assertEquals(new CoordinatorDynamicConfigsResource.CloneStatus(statusMetrics), response.getEntity()); - response = resource.getCloneStatus("hist2"); //TODO: fix + response = resource.getCloneStatus("hist2"); Assert.assertEquals(200, response.getStatus()); Assert.assertEquals(Map.of("hist2", ServerCloneStatus.unknown("hist4", "hist3")), response.getEntity()); } diff --git a/services/src/main/java/org/apache/druid/cli/CliBroker.java b/services/src/main/java/org/apache/druid/cli/CliBroker.java index e1b36f88dd48..7af834942bdf 100644 --- a/services/src/main/java/org/apache/druid/cli/CliBroker.java +++ b/services/src/main/java/org/apache/druid/cli/CliBroker.java @@ -58,10 +58,10 @@ import org.apache.druid.query.QuerySegmentWalker; import org.apache.druid.query.RetryQueryRunnerConfig; import org.apache.druid.query.lookup.LookupModule; +import org.apache.druid.server.BrokerDynamicConfigResource; import org.apache.druid.server.BrokerQueryResource; import org.apache.druid.server.ClientInfoResource; import org.apache.druid.server.ClientQuerySegmentWalker; -import org.apache.druid.server.BrokerDynamicConfigResource; import org.apache.druid.server.ResponseContextConfig; import org.apache.druid.server.SegmentManager; import org.apache.druid.server.SubqueryGuardrailHelper; From 5c7a32b24b666c846846cf8d7531114a871cc431 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Mon, 28 Apr 2025 09:02:42 +0530 Subject: [PATCH 34/38] Clean up --- .../controller/DartTableInputSpecSlicer.java | 2 +- .../client/BrokerViewOfCoordinatorConfig.java | 10 +++++-- .../client/selector/HistoricalFilter.java | 3 ++- .../server/coordinator/ServerCloneStatus.java | 5 +++- .../coordinator/duty/CloneHistoricals.java | 27 ++++++++++--------- .../CoordinatorDynamicConfigsResource.java | 12 ++++++--- 6 files changed, 38 insertions(+), 21 deletions(-) diff --git a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java index bf6b81c7dd0a..dcbdc617a479 100644 --- a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java +++ b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java @@ -164,7 +164,7 @@ public List sliceDynamic( int findWorkerForServerSelector(final ServerSelector serverSelector, final int maxNumSlices) { // Currently, Dart does not support clone query modes, all servers can be queried. - final QueryableDruidServer server = serverSelector.pick(null, CloneQueryMode.EXCLUDE_CLONES); + final QueryableDruidServer server = serverSelector.pick(null, CloneQueryMode.INCLUDE_CLONES); if (server == null) { return UNKNOWN; diff --git a/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java index d73f7d92dd59..b8860195a430 100644 --- a/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java +++ b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java @@ -60,6 +60,9 @@ public BrokerViewOfCoordinatorConfig(CoordinatorClient coordinatorClient) this.coordinatorClient = coordinatorClient; } + /** + * Return the latest {@link CoordinatorDynamicConfig}. + */ public synchronized CoordinatorDynamicConfig getDynamicConfig() { return config; @@ -119,6 +122,9 @@ public Int2ObjectRBTreeMap> getQueryableServers( return filteredHistoricals; } + /** + * Get the list of servers that should not be queried based on the cloneQueryMode parameter. + */ private synchronized Set getCurrentServersToIgnore(CloneQueryMode cloneQueryMode) { switch (cloneQueryMode) { @@ -129,8 +135,8 @@ private synchronized Set getCurrentServersToIgnore(CloneQueryMode cloneQ // Remove clones, so that only source servers are queried. return targetCloneServers; case INCLUDE_CLONES: - // Don't remove either - return ImmutableSet.of(); + // Don't remove either. + return Set.of(); default: throw DruidException.defensive("Unexpected value: [%s]", cloneQueryMode); } diff --git a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java index 85454e6e1ddc..e6ea6cab07b8 100644 --- a/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java +++ b/server/src/main/java/org/apache/druid/client/selector/HistoricalFilter.java @@ -36,7 +36,8 @@ public interface HistoricalFilter HistoricalFilter IDENTITY_FILTER = (historicalServers, mode) -> historicalServers; /** - * Perform a filtering on the historicalServers paramter, based on the cloneQueryMode paramter. + * Returns a {@link Int2ObjectRBTreeMap} after performing a filtering on the {@link QueryableDruidServer}, based + * on the cloneQueryMode paramter. The map in the parameter is not modified. */ Int2ObjectRBTreeMap> getQueryableServers( Int2ObjectRBTreeMap> historicalServers, diff --git a/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java b/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java index bf26030b0cb9..0d011fd1243e 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/ServerCloneStatus.java @@ -90,9 +90,12 @@ public State getState() return state; } + /** + * Create a {@link ServerCloneStatus} where the current status is unknown as the target server is missing. + */ public static ServerCloneStatus unknown(String sourceServer, String targetServer) { - return new ServerCloneStatus(sourceServer, targetServer, State.TARGET_SERVER_MISSING, 0, 0, 0); + return new ServerCloneStatus(sourceServer, targetServer, State.TARGET_SERVER_MISSING, -1, -1, -1); } @Override diff --git a/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java b/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java index 4505e9dda0d0..939686256eea 100644 --- a/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java +++ b/server/src/main/java/org/apache/druid/server/coordinator/duty/CloneHistoricals.java @@ -73,21 +73,21 @@ public DruidCoordinatorRuntimeParams run(DruidCoordinatorRuntimeParams params) } // Create a map of host to historical. - final Map hostToHistorical = cluster.getHistoricals() - .values() - .stream() - .flatMap(Collection::stream) - .collect(Collectors.toMap( - serverHolder -> serverHolder.getServer().getHost(), - serverHolder -> serverHolder - )); + final Map hostToHistoricalMap = cluster.getHistoricals() + .values() + .stream() + .flatMap(Collection::stream) + .collect(Collectors.toMap( + serverHolder -> serverHolder.getServer().getHost(), + serverHolder -> serverHolder + )); for (Map.Entry entry : cloneServers.entrySet()) { final String targetHistoricalName = entry.getKey(); - final ServerHolder targetServer = hostToHistorical.get(targetHistoricalName); + final ServerHolder targetServer = hostToHistoricalMap.get(targetHistoricalName); final String sourceHistoricalName = entry.getValue(); - final ServerHolder sourceServer = hostToHistorical.get(sourceHistoricalName); + final ServerHolder sourceServer = hostToHistoricalMap.get(sourceHistoricalName); if (sourceServer == null || targetServer == null) { log.error( @@ -123,13 +123,16 @@ public DruidCoordinatorRuntimeParams run(DruidCoordinatorRuntimeParams params) } } - Map newStatusMap = createCurrentStatusMap(hostToHistorical, cloneServers); + final Map newStatusMap = createCurrentStatusMap(hostToHistoricalMap, cloneServers); cloneStatusManager.updateStatus(newStatusMap); return params; } - public Map createCurrentStatusMap( + /** + * Create a status map of cloning progress based on the cloneServers mapping and its current load queue. + */ + private Map createCurrentStatusMap( Map historicalMap, Map cloneServers ) diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java index e7523a1bab11..d79c70e56a20 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java @@ -21,7 +21,6 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.common.collect.ImmutableMap; import com.sun.jersey.spi.container.ResourceFilters; import org.apache.druid.audit.AuditManager; import org.apache.druid.common.config.ConfigManager.SetResult; @@ -166,7 +165,10 @@ public Response getCloneStatus(@QueryParam("targetServer") @Nullable String targ { if (targetServer != null) { final ServerCloneStatus statusForServer = cloneStatusManager.getStatusForServer(targetServer); - return Response.ok(ImmutableMap.of(targetServer, statusForServer)).build(); + if (statusForServer == null) { + return Response.status(Response.Status.NOT_FOUND).build(); + } + return Response.ok(statusForServer).build(); } else { final CloneStatus statusForAllServers = new CloneStatus(cloneStatusManager.getStatusForAllServers()); return Response.ok(statusForAllServers).build(); @@ -174,7 +176,8 @@ public Response getCloneStatus(@QueryParam("targetServer") @Nullable String targ } /** - * Contains the current set of Brokers which have been synced with the latest {@link CoordinatorDynamicConfig}. + * Immutable class which contains the current set of Brokers which have been synced with the latest + * {@link CoordinatorDynamicConfig}. */ public static class ConfigSyncStatus { @@ -221,7 +224,8 @@ public String toString() } /** - * Contains the current set of Brokers which have been synced with the latest {@link CoordinatorDynamicConfig}. + * Immutable class which the current set of Brokers which have been synced with the latest + * {@link CoordinatorDynamicConfig}. */ public static class CloneStatus { From d66242def036375b12d954f97de676fb9fd67f37 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Mon, 28 Apr 2025 09:18:29 +0530 Subject: [PATCH 35/38] Increase retries while fetching coordinator dynamic config --- .../client/BrokerViewOfCoordinatorConfig.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java index b8860195a430..eda192f6d0e2 100644 --- a/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java +++ b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java @@ -19,16 +19,26 @@ package org.apache.druid.client; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.concurrent.GuardedBy; import com.google.inject.Inject; import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap; +import org.apache.druid.client.coordinator.Coordinator; import org.apache.druid.client.coordinator.CoordinatorClient; +import org.apache.druid.client.coordinator.CoordinatorClientImpl; import org.apache.druid.client.selector.HistoricalFilter; +import org.apache.druid.discovery.NodeRole; import org.apache.druid.error.DruidException; +import org.apache.druid.guice.annotations.EscalatedGlobal; +import org.apache.druid.guice.annotations.Json; import org.apache.druid.java.util.common.lifecycle.LifecycleStart; import org.apache.druid.java.util.common.logger.Logger; import org.apache.druid.query.CloneQueryMode; +import org.apache.druid.rpc.ServiceClientFactory; +import org.apache.druid.rpc.ServiceLocator; +import org.apache.druid.rpc.StandardRetryPolicy; import org.apache.druid.server.BrokerDynamicConfigResource; import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; @@ -55,6 +65,24 @@ public class BrokerViewOfCoordinatorConfig implements HistoricalFilter private Set sourceCloneServers; @Inject + public BrokerViewOfCoordinatorConfig( + @Json final ObjectMapper jsonMapper, + @EscalatedGlobal final ServiceClientFactory clientFactory, + @Coordinator final ServiceLocator serviceLocator + ) + { + this.coordinatorClient = + new CoordinatorClientImpl( + clientFactory.makeClient( + NodeRole.COORDINATOR.getJsonName(), + serviceLocator, + StandardRetryPolicy.builder().maxAttempts(15).build() + ), + jsonMapper + ); + } + + @VisibleForTesting public BrokerViewOfCoordinatorConfig(CoordinatorClient coordinatorClient) { this.coordinatorClient = coordinatorClient; From 5f823912a9463fa05aae2b5fdcfce243bf4cf71c Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Mon, 28 Apr 2025 10:00:43 +0530 Subject: [PATCH 36/38] Fix test --- .../server/http/CoordinatorDynamicConfigsResourceTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java index 9ec63a40509b..b889599f5952 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java @@ -32,7 +32,6 @@ import javax.ws.rs.core.Response; import java.util.List; -import java.util.Map; public class CoordinatorDynamicConfigsResourceTest { @@ -106,6 +105,6 @@ public void testGetCloneStatus() response = resource.getCloneStatus("hist2"); Assert.assertEquals(200, response.getStatus()); - Assert.assertEquals(Map.of("hist2", ServerCloneStatus.unknown("hist4", "hist3")), response.getEntity()); + Assert.assertEquals(ServerCloneStatus.unknown("hist4", "hist3"), response.getEntity()); } } From 902f18a1388b55764721a8645c366252d39b2820 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Mon, 28 Apr 2025 10:34:37 +0530 Subject: [PATCH 37/38] Move classes into separate files --- .../apache/druid/server/http/CloneStatus.java | 76 +++++++++++++ .../druid/server/http/ConfigSyncStatus.java | 75 +++++++++++++ .../CoordinatorDynamicConfigsResource.java | 101 ------------------ ...CoordinatorDynamicConfigsResourceTest.java | 4 +- 4 files changed, 153 insertions(+), 103 deletions(-) create mode 100644 server/src/main/java/org/apache/druid/server/http/CloneStatus.java create mode 100644 server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java diff --git a/server/src/main/java/org/apache/druid/server/http/CloneStatus.java b/server/src/main/java/org/apache/druid/server/http/CloneStatus.java new file mode 100644 index 000000000000..216d8cb0ec2f --- /dev/null +++ b/server/src/main/java/org/apache/druid/server/http/CloneStatus.java @@ -0,0 +1,76 @@ +/* + * 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.server.http; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; +import org.apache.druid.server.coordinator.ServerCloneStatus; + +import java.util.List; +import java.util.Objects; + +/** + * Immutable class which the current set of Brokers which have been synced with the latest + * {@link CoordinatorDynamicConfig}. + */ +public class CloneStatus +{ + private final List cloneStatus; + + @JsonCreator + public CloneStatus(@JsonProperty("cloneStatus") List cloneStatus) + { + this.cloneStatus = cloneStatus; + } + + @JsonProperty + public List getCloneStatus() + { + return cloneStatus; + } + + @Override + public boolean equals(Object o) + { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CloneStatus that = (CloneStatus) o; + return Objects.equals(cloneStatus, that.cloneStatus); + } + + @Override + public int hashCode() + { + return Objects.hashCode(cloneStatus); + } + + @Override + public String toString() + { + return "CloneStatus{" + + "cloneStatus=" + cloneStatus + + '}'; + } +} diff --git a/server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java b/server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java new file mode 100644 index 000000000000..c54648c97c68 --- /dev/null +++ b/server/src/main/java/org/apache/druid/server/http/ConfigSyncStatus.java @@ -0,0 +1,75 @@ +/* + * 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.server.http; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.druid.server.coordinator.CoordinatorDynamicConfig; + +import java.util.Objects; +import java.util.Set; + +/** + * Immutable class which contains the current set of Brokers which have been synced with the latest + * {@link CoordinatorDynamicConfig}. + */ +public class ConfigSyncStatus +{ + private final Set syncedBrokers; + + @JsonCreator + public ConfigSyncStatus(@JsonProperty("syncedBrokers") Set syncedBrokers) + { + this.syncedBrokers = syncedBrokers; + } + + @JsonProperty + public Set getSyncedBrokers() + { + return syncedBrokers; + } + + @Override + public boolean equals(Object o) + { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConfigSyncStatus that = (ConfigSyncStatus) o; + return Objects.equals(syncedBrokers, that.syncedBrokers); + } + + @Override + public int hashCode() + { + return Objects.hashCode(syncedBrokers); + } + + @Override + public String toString() + { + return "ConfigSyncStatus{" + + "syncedBrokers=" + syncedBrokers + + '}'; + } +} diff --git a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java index d79c70e56a20..93feb328a8c2 100644 --- a/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java +++ b/server/src/main/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResource.java @@ -19,8 +19,6 @@ package org.apache.druid.server.http; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; import com.sun.jersey.spi.container.ResourceFilters; import org.apache.druid.audit.AuditManager; import org.apache.druid.common.config.ConfigManager.SetResult; @@ -46,9 +44,6 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.util.List; -import java.util.Objects; -import java.util.Set; /** */ @@ -174,100 +169,4 @@ public Response getCloneStatus(@QueryParam("targetServer") @Nullable String targ return Response.ok(statusForAllServers).build(); } } - - /** - * Immutable class which contains the current set of Brokers which have been synced with the latest - * {@link CoordinatorDynamicConfig}. - */ - public static class ConfigSyncStatus - { - private final Set syncedBrokers; - - @JsonCreator - public ConfigSyncStatus(@JsonProperty("syncedBrokers") Set syncedBrokers) - { - this.syncedBrokers = syncedBrokers; - } - - @JsonProperty - public Set getSyncedBrokers() - { - return syncedBrokers; - } - - @Override - public boolean equals(Object o) - { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ConfigSyncStatus that = (ConfigSyncStatus) o; - return Objects.equals(syncedBrokers, that.syncedBrokers); - } - - @Override - public int hashCode() - { - return Objects.hashCode(syncedBrokers); - } - - @Override - public String toString() - { - return "ConfigSyncStatus{" + - "syncedBrokers=" + syncedBrokers + - '}'; - } - } - - /** - * Immutable class which the current set of Brokers which have been synced with the latest - * {@link CoordinatorDynamicConfig}. - */ - public static class CloneStatus - { - private final List cloneStatus; - - @JsonCreator - public CloneStatus(@JsonProperty("cloneStatus") List cloneStatus) - { - this.cloneStatus = cloneStatus; - } - - @JsonProperty - public List getCloneStatus() - { - return cloneStatus; - } - - @Override - public boolean equals(Object o) - { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - CloneStatus that = (CloneStatus) o; - return Objects.equals(cloneStatus, that.cloneStatus); - } - - @Override - public int hashCode() - { - return Objects.hashCode(cloneStatus); - } - - @Override - public String toString() - { - return "CloneStatus{" + - "cloneStatus=" + cloneStatus + - '}'; - } - } } diff --git a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java index b889599f5952..87d99b0759bd 100644 --- a/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java +++ b/server/src/test/java/org/apache/druid/server/http/CoordinatorDynamicConfigsResourceTest.java @@ -72,7 +72,7 @@ public void testGetBrokerStatus() Assert.assertEquals(200, response.getStatus()); - CoordinatorDynamicConfigsResource.ConfigSyncStatus expected = new CoordinatorDynamicConfigsResource.ConfigSyncStatus( + ConfigSyncStatus expected = new ConfigSyncStatus( ImmutableSet.of( new BrokerSyncStatus("host1", 8080, 1000) ) @@ -101,7 +101,7 @@ public void testGetCloneStatus() ); Response response = resource.getCloneStatus(null); Assert.assertEquals(200, response.getStatus()); - Assert.assertEquals(new CoordinatorDynamicConfigsResource.CloneStatus(statusMetrics), response.getEntity()); + Assert.assertEquals(new CloneStatus(statusMetrics), response.getEntity()); response = resource.getCloneStatus("hist2"); Assert.assertEquals(200, response.getStatus()); From 455edf3e5b5cfce5bf83cf2d568bfa417fd69d72 Mon Sep 17 00:00:00 2001 From: Adarsh Sanjeev Date: Mon, 28 Apr 2025 11:06:08 +0530 Subject: [PATCH 38/38] Rename enum --- .../controller/DartTableInputSpecSlicer.java | 4 ++-- .../apache/druid/query/CloneQueryMode.java | 6 ++--- .../org/apache/druid/query/QueryContexts.java | 2 +- .../apache/druid/query/QueryContextsTest.java | 2 +- .../client/BrokerViewOfCoordinatorConfig.java | 6 ++--- .../druid/client/BrokerServerViewTest.java | 16 ++++++------- ...ingClusteredClientCacheKeyManagerTest.java | 24 +++++++++---------- .../druid/client/DirectDruidClientTest.java | 2 +- ...ectionCountServerSelectorStrategyTest.java | 4 ++-- .../selector/TierSelectorStrategyTest.java | 8 +++---- 10 files changed, 37 insertions(+), 37 deletions(-) diff --git a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java index dcbdc617a479..00813d0f2fb7 100644 --- a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java +++ b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/dart/controller/DartTableInputSpecSlicer.java @@ -164,7 +164,7 @@ public List sliceDynamic( int findWorkerForServerSelector(final ServerSelector serverSelector, final int maxNumSlices) { // Currently, Dart does not support clone query modes, all servers can be queried. - final QueryableDruidServer server = serverSelector.pick(null, CloneQueryMode.INCLUDE_CLONES); + final QueryableDruidServer server = serverSelector.pick(null, CloneQueryMode.INCLUDECLONES); if (server == null) { return UNKNOWN; @@ -282,7 +282,7 @@ static boolean shouldIncludeSegment(final ServerSelector serverSelector) int numOtherServers = 0; // Currently, Dart does not support clone query modes, all servers can be queried. - for (final DruidServerMetadata server : serverSelector.getAllServers(CloneQueryMode.INCLUDE_CLONES)) { + for (final DruidServerMetadata server : serverSelector.getAllServers(CloneQueryMode.INCLUDECLONES)) { if (SegmentSource.REALTIME.getUsedServerTypes().contains(server.getType())) { numRealtimeServers++; } else { diff --git a/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java b/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java index d0287dfe8cc2..643c1dcb4036 100644 --- a/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java +++ b/processing/src/main/java/org/apache/druid/query/CloneQueryMode.java @@ -31,15 +31,15 @@ public enum CloneQueryMode * For each ongoing cloning, do not query the source server that is being cloned. Other servers which are not * participating in any cloning will still be queried. */ - PREFER_CLONES("preferClones"), + PREFERCLONES("preferClones"), /** * Consider both clones and their source servers for querying. */ - INCLUDE_CLONES("includeClones"), + INCLUDECLONES("includeClones"), /** * Do not query clone servers. */ - EXCLUDE_CLONES("excludeClones"); + EXCLUDECLONES("excludeClones"); private final String name; diff --git a/processing/src/main/java/org/apache/druid/query/QueryContexts.java b/processing/src/main/java/org/apache/druid/query/QueryContexts.java index dc7bcf1163be..ef48d67fbf54 100644 --- a/processing/src/main/java/org/apache/druid/query/QueryContexts.java +++ b/processing/src/main/java/org/apache/druid/query/QueryContexts.java @@ -150,7 +150,7 @@ public class QueryContexts public static final boolean DEFAULT_ENABLE_JOIN_FILTER_PUSH_DOWN = true; public static final boolean DEFAULT_ENABLE_JOIN_FILTER_REWRITE = true; public static final boolean DEFAULT_ENABLE_JOIN_FILTER_REWRITE_VALUE_COLUMN_FILTERS = false; - public static final CloneQueryMode DEFAULT_CLONE_QUERY_MODE = CloneQueryMode.EXCLUDE_CLONES; + public static final CloneQueryMode DEFAULT_CLONE_QUERY_MODE = CloneQueryMode.EXCLUDECLONES; public static final boolean DEFAULT_ENABLE_REWRITE_JOIN_TO_FILTER = true; public static final long DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE = 10000; public static final boolean DEFAULT_ENABLE_SQL_JOIN_LEFT_SCAN_DIRECT = false; diff --git a/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java b/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java index 99ef2fad8dd0..735fabe0f8b3 100644 --- a/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java +++ b/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java @@ -148,7 +148,7 @@ public void testDefaultPlanTimeBoundarySql() public void testDefaultCloneQueryMode() { Assert.assertEquals( - CloneQueryMode.EXCLUDE_CLONES, + CloneQueryMode.EXCLUDECLONES, QueryContext.empty().getCloneQueryMode() ); } diff --git a/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java index eda192f6d0e2..5334fff0731b 100644 --- a/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java +++ b/server/src/main/java/org/apache/druid/client/BrokerViewOfCoordinatorConfig.java @@ -156,13 +156,13 @@ public Int2ObjectRBTreeMap> getQueryableServers( private synchronized Set getCurrentServersToIgnore(CloneQueryMode cloneQueryMode) { switch (cloneQueryMode) { - case PREFER_CLONES: + case PREFERCLONES: // Remove servers being cloned targets, so that clones are queried. return sourceCloneServers; - case EXCLUDE_CLONES: + case EXCLUDECLONES: // Remove clones, so that only source servers are queried. return targetCloneServers; - case INCLUDE_CLONES: + case INCLUDECLONES: // Don't remove either. return Set.of(); default: diff --git a/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java b/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java index ec310d592226..707d61b140ba 100644 --- a/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java +++ b/server/src/test/java/org/apache/druid/client/BrokerServerViewTest.java @@ -133,7 +133,7 @@ public void testSingleServerAddedRemovedSegment() throws Exception ServerSelector selector = (actualPartitionHolder.iterator().next()).getObject(); Assert.assertFalse(selector.isEmpty()); Assert.assertEquals(segment, selector.getSegment()); - Assert.assertEquals(druidServer, selector.pick(null, CloneQueryMode.EXCLUDE_CLONES).getServer()); + Assert.assertEquals(druidServer, selector.pick(null, CloneQueryMode.EXCLUDECLONES).getServer()); Assert.assertNotNull(timeline.findChunk(intervals, "v1", partition)); unannounceSegmentForServer(druidServer, segment, zkPathsConfig); @@ -392,9 +392,9 @@ public void testMultipleTiers() throws Exception // Verify that the ServerSelector always picks Tier 1 for (int i = 0; i < 5; ++i) { - Assert.assertEquals(server21, selector.pick(null, CloneQueryMode.EXCLUDE_CLONES).getServer()); + Assert.assertEquals(server21, selector.pick(null, CloneQueryMode.EXCLUDECLONES).getServer()); } - Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDE_CLONES)); + Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDECLONES)); } @Test @@ -452,9 +452,9 @@ public void testRealtimeTasksNotWatched() throws Exception // Verify that the ServerSelector always picks the Historical server for (int i = 0; i < 5; ++i) { - Assert.assertEquals(historicalServer, selector.pick(null, CloneQueryMode.EXCLUDE_CLONES).getServer()); + Assert.assertEquals(historicalServer, selector.pick(null, CloneQueryMode.EXCLUDECLONES).getServer()); } - Assert.assertEquals(Collections.singletonList(historicalServer.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDE_CLONES)); + Assert.assertEquals(Collections.singletonList(historicalServer.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDECLONES)); } @Test @@ -514,9 +514,9 @@ public void testIgnoredTiers() throws Exception // Verify that the ServerSelector always picks Tier 1 for (int i = 0; i < 5; ++i) { - Assert.assertEquals(server21, selector.pick(null, CloneQueryMode.EXCLUDE_CLONES).getServer()); + Assert.assertEquals(server21, selector.pick(null, CloneQueryMode.EXCLUDECLONES).getServer()); } - Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDE_CLONES)); + Assert.assertEquals(Collections.singletonList(server21.getMetadata()), selector.getCandidates(2, CloneQueryMode.EXCLUDECLONES)); } @Test(expected = ISE.class) @@ -596,7 +596,7 @@ private void assertValues( ServerSelector selector = ((SingleElementPartitionChunk) actualPartitionHolder.iterator() .next()).getObject(); Assert.assertFalse(selector.isEmpty()); - Assert.assertEquals(expectedPair.rhs.rhs.lhs, selector.pick(null, CloneQueryMode.EXCLUDE_CLONES).getServer()); + Assert.assertEquals(expectedPair.rhs.rhs.lhs, selector.pick(null, CloneQueryMode.EXCLUDECLONES).getServer()); Assert.assertEquals(expectedPair.rhs.rhs.rhs, selector.getSegment()); } } diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java index 76846935f940..c27a0537ae2c 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientCacheKeyManagerTest.java @@ -87,7 +87,7 @@ public void testComputeEtag_nonHistorical() makeHistoricalServerSelector(0), makeRealtimeServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, QUERY_CACHE_KEY); + String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDECLONES, QUERY_CACHE_KEY); Assert.assertNull(actual); } @@ -100,14 +100,14 @@ public void testComputeEtag_DifferentHistoricals() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, QUERY_CACHE_KEY); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDECLONES, QUERY_CACHE_KEY); Assert.assertNotNull(actual1); selectors = ImmutableSet.of( makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, QUERY_CACHE_KEY); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDECLONES, QUERY_CACHE_KEY); Assert.assertNotNull(actual2); Assert.assertEquals("cache key should not change for same server selectors", actual1, actual2); @@ -115,7 +115,7 @@ public void testComputeEtag_DifferentHistoricals() makeHistoricalServerSelector(2), makeHistoricalServerSelector(1) ); - String actual3 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, QUERY_CACHE_KEY); + String actual3 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDECLONES, QUERY_CACHE_KEY); Assert.assertNotNull(actual3); Assert.assertNotEquals(actual1, actual3); } @@ -129,10 +129,10 @@ public void testComputeEtag_DifferentQueryCacheKey() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, new byte[]{1, 2}); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDECLONES, new byte[]{1, 2}); Assert.assertNotNull(actual1); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, new byte[]{3, 4}); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDECLONES, new byte[]{3, 4}); Assert.assertNotNull(actual2); Assert.assertNotEquals(actual1, actual2); } @@ -147,14 +147,14 @@ public void testComputeEtag_nonJoinDataSource() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, FULL_QUERY_CACHE_KEY); + String actual1 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDECLONES, FULL_QUERY_CACHE_KEY); Assert.assertNotNull(actual1); selectors = ImmutableSet.of( makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, null); + String actual2 = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDECLONES, null); Assert.assertNotNull(actual2); Assert.assertEquals(actual1, actual2); } @@ -170,7 +170,7 @@ public void testComputeEtag_joinWithUnsupportedCaching() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDECLONES, null); Assert.assertNull(actual); } @@ -188,7 +188,7 @@ public void testComputeEtag_noEffectifBySegment() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDECLONES, null); Assert.assertNotNull(actual); } @@ -207,7 +207,7 @@ public void testComputeEtag_noEffectIfUseAndPopulateFalse() makeHistoricalServerSelector(1), makeHistoricalServerSelector(1) ); - String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDE_CLONES, null); + String actual = keyManager.computeResultLevelCachingEtag(selectors, CloneQueryMode.EXCLUDECLONES, null); Assert.assertNotNull(actual); } @@ -304,7 +304,7 @@ private SegmentServerSelector makeServerSelector(boolean isHistorical, int parti 0 ); expect(server.isSegmentReplicationTarget()).andReturn(isHistorical).anyTimes(); - expect(serverSelector.pick(query, CloneQueryMode.EXCLUDE_CLONES)).andReturn(queryableDruidServer).anyTimes(); + expect(serverSelector.pick(query, CloneQueryMode.EXCLUDECLONES)).andReturn(queryableDruidServer).anyTimes(); expect(queryableDruidServer.getServer()).andReturn(server).anyTimes(); expect(serverSelector.getSegment()).andReturn(segment).anyTimes(); replay(serverSelector, queryableDruidServer, server); diff --git a/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java b/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java index 1ebba1736924..a86a07c8f866 100644 --- a/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java +++ b/server/src/test/java/org/apache/druid/client/DirectDruidClientTest.java @@ -248,7 +248,7 @@ public void testRun() throws Exception Assert.assertEquals(2, client2.getNumOpenConnections()); - Assert.assertEquals(serverSelector.pick(null, CloneQueryMode.EXCLUDE_CLONES), queryableDruidServer2); + Assert.assertEquals(serverSelector.pick(null, CloneQueryMode.EXCLUDECLONES), queryableDruidServer2); EasyMock.verify(httpClient); } diff --git a/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java b/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java index dfc3a49dfbd0..950d1f80556c 100644 --- a/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java +++ b/server/src/test/java/org/apache/druid/client/selector/ConnectionCountServerSelectorStrategyTest.java @@ -51,7 +51,7 @@ public void testDifferentConnectionCount() ServerSelector serverSelector = initSelector(s1, s2, s3); for (int i = 0; i < 100; ++i) { - Assert.assertEquals(s2, serverSelector.pick(null, CloneQueryMode.EXCLUDE_CLONES)); + Assert.assertEquals(s2, serverSelector.pick(null, CloneQueryMode.EXCLUDECLONES)); } } @@ -64,7 +64,7 @@ public void testBalancerTieBreaking() Set pickedServers = new HashSet<>(); for (int i = 0; i < 100; ++i) { - pickedServers.add(serverSelector.pick(null, CloneQueryMode.EXCLUDE_CLONES).getServer().getName()); + pickedServers.add(serverSelector.pick(null, CloneQueryMode.EXCLUDECLONES).getServer().getName()); } Assert.assertTrue( "Multiple servers should be selected when the number of connections is equal.", diff --git a/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java b/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java index 8aac8184104a..335b0ef7c502 100644 --- a/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java +++ b/server/src/test/java/org/apache/druid/client/selector/TierSelectorStrategyTest.java @@ -242,10 +242,10 @@ private void testTierSelectorStrategy( serverSelector.addServerAndUpdateSegment(server, serverSelector.getSegment()); } - Assert.assertEquals(expectedSelection[0], serverSelector.pick(null, CloneQueryMode.EXCLUDE_CLONES)); - Assert.assertEquals(expectedSelection[0], serverSelector.pick(EasyMock.createMock(Query.class), CloneQueryMode.EXCLUDE_CLONES)); - Assert.assertEquals(expectedCandidates, serverSelector.getCandidates(-1, CloneQueryMode.EXCLUDE_CLONES)); - Assert.assertEquals(expectedCandidates.subList(0, 2), serverSelector.getCandidates(2, CloneQueryMode.EXCLUDE_CLONES)); + Assert.assertEquals(expectedSelection[0], serverSelector.pick(null, CloneQueryMode.EXCLUDECLONES)); + Assert.assertEquals(expectedSelection[0], serverSelector.pick(EasyMock.createMock(Query.class), CloneQueryMode.EXCLUDECLONES)); + Assert.assertEquals(expectedCandidates, serverSelector.getCandidates(-1, CloneQueryMode.EXCLUDECLONES)); + Assert.assertEquals(expectedCandidates.subList(0, 2), serverSelector.getCandidates(2, CloneQueryMode.EXCLUDECLONES)); } @Test