Skip to content

Commit fc3d1cf

Browse files
authored
Merge branch 'apache:master' into reverse_ldap_lookup_basic-auth
2 parents 05053ed + 8ce2f36 commit fc3d1cf

71 files changed

Lines changed: 3191 additions & 396 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

distribution/docker/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ RUN export DEBIAN_FRONTEND=noninteractive \
3535

3636
COPY . /src
3737
WORKDIR /src
38-
RUN --mount=type=cache,target=/root/.m2 if [ "$BUILD_FROM_SOURCE" = "true" ]; then \
38+
RUN --mount=type=cache,target=/root/.m2,sharing=locked if [ "$BUILD_FROM_SOURCE" = "true" ]; then \
3939
mvn -B -ff -q \
4040
install \
4141
-Pdist,bundle-contrib-exts \
4242
-Pskip-static-checks,skip-tests \
4343
-Dmaven.javadoc.skip=true -T1C \
4444
; fi
4545

46-
RUN --mount=type=cache,target=/root/.m2 VERSION=$(mvn -B -q org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \
46+
RUN --mount=type=cache,target=/root/.m2,sharing=locked VERSION=$(mvn -B -q org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \
4747
-Dexpression=project.version -DforceStdout=true \
4848
) \
4949
&& tar -zxf ./distribution/target/apache-druid-${VERSION}-bin.tar.gz -C /opt \

docs/configuration/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2231,6 +2231,7 @@ Supported runtime properties:
22312231
|`druid.query.groupBy.maxMergingDictionarySize`|Maximum amount of heap space (approximately) to use for per-query string dictionaries. When the dictionary exceeds this size, a spill to disk will be triggered. See [groupBy memory tuning and resource limits](../querying/groupbyquery.md#memory-tuning-and-resource-limits) for details.|100000000|
22322232
|`druid.query.groupBy.maxOnDiskStorage`|Maximum amount of disk space to use, per-query, for spilling result sets to disk when either the merging buffer or the dictionary fills up. Queries that exceed this limit will fail. Set to zero to disable disk spilling.|0 (disabled)|
22332233
|`druid.query.groupBy.maxSpillFileCount`|Maximum number of spill files allowed per GroupBy query. Queries that exceed this limit will fail. See [groupBy memory tuning and resource limits](../querying/groupbyquery.md#memory-tuning-and-resource-limits) for details.|Integer.MAX_VALUE (unlimited)|
2234+
|`druid.query.groupBy.minSpillFileSize`|Minimum number of bytes that must accumulate across pending in-memory spill runs before they are flushed as a single file to disk. Smaller spills are batched in heap memory to avoid creating many tiny files. Higher values reduce file count but increase heap usage.|1048576 (1 MiB)|
22342235
|`druid.query.groupBy.defaultOnDiskStorage`|Default amount of disk space to use, per-query, for spilling the result sets to disk when either the merging buffer or the dictionary fills up. Set to zero to disable disk spilling for queries which don't override `maxOnDiskStorage` in their context.|`druid.query.groupBy.maxOnDiskStorage`|
22352236

22362237
Supported query contexts:
@@ -2241,6 +2242,7 @@ Supported query contexts:
22412242
|`maxMergingDictionarySize`|Can be used to lower the value of `druid.query.groupBy.maxMergingDictionarySize` for this query.|
22422243
|`maxOnDiskStorage`|Can be used to set `maxOnDiskStorage` to a value between 0 and `druid.query.groupBy.maxOnDiskStorage` for this query. If this query context override exceeds `druid.query.groupBy.maxOnDiskStorage`, the query will use `druid.query.groupBy.maxOnDiskStorage`. Omitting this from the query context will cause the query to use `druid.query.groupBy.defaultOnDiskStorage` for `maxOnDiskStorage`|
22432244
|`maxSpillFileCount`|Can be used to override the value of `druid.query.groupBy.maxSpillFileCount` for this query.|
2245+
|`minSpillFileSize`|Can be used to override the value of `druid.query.groupBy.minSpillFileSize` for this query.|
22442246

22452247
### Advanced configurations
22462248

docs/development/extensions-core/k8s-jobs.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,16 @@ All three examples below are equivalent.
763763

764764
In all the above cases, Druid will match the selector to any value of task type. Druid applies similar logic for `dataSource`. For `context.tags` setting `null` or an empty object `{}` is equivalent.
765765

766+
##### Override pod template via context
767+
768+
Set the `podTemplateSelectionKey` key in a task's context to pick a configured pod template directly, bypassing the selection strategy. The value is the same `selectionKey` used by `selectorBased` strategy (i.e. the suffix of `druid.indexer.runner.k8s.podTemplate.<selectionKey>`).
769+
770+
```json
771+
"context": { "podTemplateSelectionKey": "podSpec1" }
772+
```
773+
774+
This is gated by the runtime property `druid.indexer.runner.allowTaskPodTemplateSelection`, which defaults to `false`. If the key doesn't match any configured template, the task fails to launch.
775+
766776
#### Running Task Pods in Another Namespace
767777

768778
It is possible to run task pods in a different namespace from the rest of your Druid cluster.

docs/ingestion/supervisor.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ The following table outlines the configuration properties for `autoScalerConfig`
7878
|`enableTaskAutoScaler`|Enables the autoscaler. If not specified, Druid disables the autoscaler even when `autoScalerConfig` is not null.|No|`false`|
7979
|`taskCountMax`|The maximum number of ingestion tasks. Must be greater than or equal to `taskCountMin`. If `taskCountMax` is greater than the number of Kafka partitions or Kinesis shards, Druid sets the maximum number of reading tasks to the number of Kafka partitions or Kinesis shards and ignores `taskCountMax`.|Yes||
8080
|`taskCountMin`|The minimum number of ingestion tasks. When you enable the autoscaler, Druid computes the initial number of tasks to launch by checking the configs in the following order: `taskCountStart`, then `taskCount` (in `ioConfig`), then `taskCountMin`.|Yes||
81-
|`taskCountStart`|Optional config to specify the number of ingestion tasks to start with. When you enable the autoscaler, Druid computes the initial number of tasks to launch by checking the configs in the following order: `taskCountStart`, then `taskCount` (in `ioConfig`), then `taskCountMin`.|No|`taskCount` or `taskCountMin`|
81+
|`taskCountStart`|Optional config to specify the number of ingestion tasks to start with. If `taskCountStart` is provided on POST of a supervisor, it takes priority and the `taskCount` is reset to `taskCountStart` at that time.|No|`taskCount` or `taskCountMin`|
8282
|`minScaleUpDelay`|Minimum cooldown duration between scale-up actions, specified as an ISO-8601 duration string. Falls back to `minTriggerScaleActionFrequencyMillis` if not set.|No||
8383
|`minScaleDownDelay`|Minimum cooldown duration between scale-down actions, specified as an ISO-8601 duration string. Falls back to `minTriggerScaleActionFrequencyMillis` if not set.|No||
8484
|`minTriggerScaleActionFrequencyMillis`|**Deprecated.** Use `minScaleUpDelay` and `minScaleDownDelay` instead. Minimum time interval in milliseconds between scale actions, used as the fallback when the Duration-based fields are not set.|No|600000|

docs/querying/groupbyquery.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,13 +358,15 @@ Supported runtime properties:
358358
|`druid.query.groupBy.maxMergingDictionarySize`|Maximum amount of heap space (approximately) to use for per-query string dictionaries. When the dictionary exceeds this size, a spill to disk will be triggered. If set to `0` (automatic), each query's dictionary uses 30% of the Java heap divided by `druid.processing.numMergeBuffers`, or 1GB, whichever is smaller.<br /><br />See [Memory tuning and resource limits](#memory-tuning-and-resource-limits) for details on changing this property.|0 (automatic)|
359359
|`druid.query.groupBy.maxOnDiskStorage`|Maximum amount of disk space to use, per-query, for spilling result sets to disk when either the merging buffer or the dictionary fills up. Queries that exceed this limit will fail. Set to zero to disable disk spilling.|0 (disabled)|
360360
|`druid.query.groupBy.maxSpillFileCount`|Maximum number of spill files allowed per GroupBy query. Queries that exceed this limit will fail.<br /><br />See [Memory tuning and resource limits](#memory-tuning-and-resource-limits) for details on changing this property.|Integer.MAX_VALUE (unlimited)|
361+
|`druid.query.groupBy.minSpillFileSize`|Minimum number of bytes that must accumulate across pending in-memory spill runs before they are flushed as a single file to disk. Smaller spills are batched in heap memory to avoid creating many tiny files. Higher values reduce file count but increase heap usage.|1048576 (1 MiB)|
361362

362363
Supported query contexts:
363364

364365
|Key|Description|
365366
|---|-----------|
366367
|`maxOnDiskStorage`|Can be used to lower the value of `druid.query.groupBy.maxOnDiskStorage` for this query.|
367368
|`maxSpillFileCount`|Can be used to override the value of `druid.query.groupBy.maxSpillFileCount` for this query.|
369+
|`minSpillFileSize`|Can be used to override the value of `druid.query.groupBy.minSpillFileSize` for this query.|
368370

369371
### Advanced configurations
370372

embedded-tests/src/test/java/org/apache/druid/testing/embedded/indexing/IngestionSmokeTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ public void test_runIndexTask_andKillData()
189189
.hasService("druid/broker")
190190
);
191191

192+
waitForNextCoordinatorCacheSync();
193+
waitForNextBrokerCacheSync();
194+
192195
cluster.callApi().verifySqlQuery("SELECT * FROM sys.segments WHERE datasource='%s'", dataSource, "");
193196

194197
// Kill all unused segments
@@ -430,6 +433,14 @@ protected void waitForNextCoordinatorCacheSync()
430433
);
431434
}
432435

436+
protected void waitForNextBrokerCacheSync()
437+
{
438+
eventCollector.latchableEmitter().waitForNextEvent(
439+
event -> event.hasMetricName("segment/metadataCache/sync/time")
440+
.hasService("druid/broker")
441+
);
442+
}
443+
433444
/**
434445
* Verifies the total number of used segments in {@link #dataSource}.
435446
*/

embedded-tests/src/test/java/org/apache/druid/testing/embedded/query/QueryVirtualStorageTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
class QueryVirtualStorageTest extends EmbeddedClusterTestBase
6868
{
6969
// size of wiki segments, adjust this if segment size changes for some reason
70-
private static final long SIZE_BYTES = 3776682L;
70+
private static final long SIZE_BYTES = 3777834L;
7171
private static final long CACHE_SIZE = HumanReadableBytes.parse("1MiB");
7272
private static final long MAX_SIZE = HumanReadableBytes.parse("100MiB");
7373

@@ -294,7 +294,8 @@ void testQueryTooMuchDataButWithDart()
294294
Assertions.assertTrue(segmentChannelCounters.getLoadFiles()[0] > 0 && segmentChannelCounters.getLoadFiles()[0] <= segmentChannelCounters.getFiles()[0]);
295295
// size of all segments at time of writing, possibly we have to load all of them, but possibly less depending on
296296
// test order
297-
Assertions.assertTrue(segmentChannelCounters.getLoadBytes()[0] > 0 && segmentChannelCounters.getLoadBytes()[0] <= SIZE_BYTES);
297+
Assertions.assertTrue(segmentChannelCounters.getLoadBytes()[0] > 0);
298+
Assertions.assertTrue(segmentChannelCounters.getLoadBytes()[0] <= SIZE_BYTES);
298299
Assertions.assertTrue(segmentChannelCounters.getLoadTime()[0] > 0);
299300
Assertions.assertTrue(segmentChannelCounters.getLoadWait()[0] > 0);
300301
}

extensions-core/kafka-indexing-service/src/test/java/org/apache/druid/indexing/kafka/supervisor/KafkaSupervisorIOConfigTest.java

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ public void testAutoScalingConfigSerde() throws JsonProcessingException
381381
false,
382382
null
383383
);
384-
Assert.assertEquals(5, kafkaSupervisorIOConfig.getTaskCount().intValue());
384+
Assert.assertEquals(1, kafkaSupervisorIOConfig.getTaskCount());
385385

386386
Assert.assertThrows(
387387
"taskCountMin <= taskCountStart <= taskCountMax",
@@ -400,6 +400,51 @@ public void testAutoScalingConfigSerde() throws JsonProcessingException
400400
);
401401
}
402402

403+
@Test
404+
public void testTaskCountStartFallbackAndExplicitFlag()
405+
{
406+
final Map<String, Object> autoScalerConfig = ImmutableMap.of(
407+
"enableTaskAutoScaler", true,
408+
"taskCountMin", 1,
409+
"taskCountMax", 10,
410+
"taskCountStart", 5
411+
);
412+
413+
Assert.assertEquals(7, makeIOConfig(7, autoScalerConfig).getTaskCount());
414+
Assert.assertTrue(makeIOConfig(7, autoScalerConfig).isTaskCountExplicit());
415+
416+
Assert.assertEquals(5, makeIOConfig(null, autoScalerConfig).getTaskCount());
417+
Assert.assertFalse(makeIOConfig(null, autoScalerConfig).isTaskCountExplicit());
418+
}
419+
420+
private KafkaSupervisorIOConfig makeIOConfig(Integer taskCount, Map<String, Object> autoScalerConfig)
421+
{
422+
return new KafkaSupervisorIOConfig(
423+
"test",
424+
null,
425+
null,
426+
1,
427+
taskCount,
428+
new Period("PT1H"),
429+
ImmutableMap.of("bootstrap.servers", "localhost:8082"),
430+
mapper.convertValue(autoScalerConfig, LagBasedAutoScalerConfig.class),
431+
LagAggregator.DEFAULT,
432+
KafkaSupervisorIOConfig.DEFAULT_POLL_TIMEOUT_MILLIS,
433+
new Period("P1D"),
434+
new Period("PT30S"),
435+
true,
436+
new Period("PT30M"),
437+
null,
438+
null,
439+
null,
440+
null,
441+
null,
442+
null,
443+
false,
444+
null
445+
);
446+
}
447+
403448
@Test
404449
public void testIdleConfigSerde() throws JsonProcessingException
405450
{

extensions-core/kafka-indexing-service/src/test/java/org/apache/druid/indexing/kafka/supervisor/KafkaSupervisorSpecTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@
3030
import org.apache.druid.indexing.overlord.IndexerMetadataStorageCoordinator;
3131
import org.apache.druid.indexing.overlord.TaskMaster;
3232
import org.apache.druid.indexing.overlord.TaskStorage;
33+
import org.apache.druid.indexing.overlord.supervisor.SupervisorSpec;
3334
import org.apache.druid.indexing.overlord.supervisor.SupervisorStateManagerConfig;
35+
import org.apache.druid.indexing.seekablestream.supervisor.LagAggregator;
36+
import org.apache.druid.indexing.seekablestream.supervisor.autoscaler.CostBasedAutoScalerConfig;
3437
import org.apache.druid.jackson.DefaultObjectMapper;
3538
import org.apache.druid.java.util.common.StringUtils;
3639
import org.apache.druid.java.util.common.granularity.Granularities;
@@ -422,6 +425,46 @@ public void testSuspendResume() throws IOException
422425
Assert.assertFalse(runningSpec.isSuspended());
423426
}
424427

428+
@Test
429+
public void testTaskCountSerdeRoundTrip() throws IOException
430+
{
431+
// A persisted taskCount must survive a serialize/deserialize round-trip even when
432+
// autoScalerConfig.taskCountStart is set.
433+
final CostBasedAutoScalerConfig autoScalerConfig =
434+
CostBasedAutoScalerConfig.builder()
435+
.enableTaskAutoScaler(true)
436+
.taskCountMin(1)
437+
.taskCountMax(100)
438+
.taskCountStart(25)
439+
.build();
440+
441+
final KafkaSupervisorSpec spec = new KafkaSupervisorSpecBuilder()
442+
.withDataSchema(
443+
schema -> schema
444+
.withTimestamp(TimestampSpec.DEFAULT)
445+
.withAggregators(new CountAggregatorFactory("rows"))
446+
.withGranularity(new UniformGranularitySpec(Granularities.DAY, Granularities.NONE, null))
447+
)
448+
.withIoConfig(
449+
ioConfig -> ioConfig
450+
.withJsonInputFormat()
451+
.withConsumerProperties(Map.of("bootstrap.servers", "localhost:9092"))
452+
.withTaskCount(25)
453+
.withAutoScalerConfig(autoScalerConfig)
454+
.withLagAggregator(LagAggregator.DEFAULT)
455+
)
456+
.build("testDs", "metrics");
457+
458+
// Mutate taskCount the same way SeekableStreamSupervisor.changeTaskCountInIOConfig does,
459+
// and verify that the mutation is picked up by serialization.
460+
spec.getIoConfig().setTaskCount(50);
461+
final byte[] payload = mapper.writeValueAsBytes(spec);
462+
final KafkaSupervisorSpec roundTripped =
463+
(KafkaSupervisorSpec) mapper.readValue(payload, SupervisorSpec.class);
464+
Assert.assertEquals(50, roundTripped.getIoConfig().getTaskCount());
465+
Assert.assertTrue(roundTripped.getIoConfig().isTaskCountExplicit());
466+
}
467+
425468
@Test
426469
public void test_validateSpecUpdateTo()
427470
{

extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/KubernetesTaskRunnerConfig.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ public interface KubernetesTaskRunnerConfig
9191
*/
9292
Period getK8sSharedInformerResyncPeriod();
9393

94+
/**
95+
* Whether tasks may select a configured pod template via the {@code DruidK8sConstants.TASK_CONTEXT_POD_TEMPLATE_SELECTION_KEY}
96+
* task context key, overriding the configured {@code PodTemplateSelectStrategy}.
97+
*/
98+
boolean isAllowTaskPodTemplateSelection();
99+
94100
static Builder builder()
95101
{
96102
return new Builder();
@@ -121,6 +127,7 @@ public static class Builder
121127
private Period logSaveTimeout;
122128
private boolean useK8sSharedInformers;
123129
private Period k8sSharedInformerResyncPeriod;
130+
private boolean allowTaskPodTemplateSelection;
124131

125132
public Builder()
126133
{
@@ -265,6 +272,12 @@ public Builder withK8sSharedInformerResyncPeriod(Period k8sSharedInformerResyncP
265272
return this;
266273
}
267274

275+
public Builder withAllowTaskPodTemplateSelection(boolean allowTaskPodTemplateSelection)
276+
{
277+
this.allowTaskPodTemplateSelection = allowTaskPodTemplateSelection;
278+
return this;
279+
}
280+
268281
public KubernetesTaskRunnerStaticConfig build()
269282
{
270283
return new KubernetesTaskRunnerStaticConfig(
@@ -290,7 +303,8 @@ public KubernetesTaskRunnerStaticConfig build()
290303
this.capacity,
291304
this.taskJoinTimeout,
292305
this.useK8sSharedInformers,
293-
this.k8sSharedInformerResyncPeriod
306+
this.k8sSharedInformerResyncPeriod,
307+
this.allowTaskPodTemplateSelection
294308
);
295309
}
296310
}

0 commit comments

Comments
 (0)