This is an automated email from the ASF dual-hosted git repository.

capistrant pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new e6b0ce9a4c5 enhance the cluster compaction config view to allow 
configuring mostFragmentedFirst more easily for operators (#19242)
e6b0ce9a4c5 is described below

commit e6b0ce9a4c579a63f258396c18acf801fd5dee73
Author: Lucas Capistrant <[email protected]>
AuthorDate: Wed Apr 1 15:05:35 2026 -0500

    enhance the cluster compaction config view to allow configuring 
mostFragmentedFirst more easily for operators (#19242)
---
 .../compaction-dynamic-config-completions.ts       |  46 ++++++++-
 .../compaction-dynamic-config.tsx                  | 115 +++++++++++++++++++--
 2 files changed, 151 insertions(+), 10 deletions(-)

diff --git 
a/web-console/src/dialogs/compaction-dynamic-config-dialog/compaction-dynamic-config-completions.ts
 
b/web-console/src/dialogs/compaction-dynamic-config-dialog/compaction-dynamic-config-completions.ts
index 1fa4b7b2416..8019d9695d3 100644
--- 
a/web-console/src/dialogs/compaction-dynamic-config-dialog/compaction-dynamic-config-completions.ts
+++ 
b/web-console/src/dialogs/compaction-dynamic-config-dialog/compaction-dynamic-config-completions.ts
@@ -76,16 +76,49 @@ export const COMPACTION_DYNAMIC_CONFIG_COMPLETIONS: 
JsonCompletionRule[] = [
       { value: '2147483647', documentation: 'Maximum value (default)' },
     ],
   },
-  // compactionPolicy object properties
+  // compactionPolicy object properties (newestSegmentFirst)
   {
     path: '$.compactionPolicy',
     isObject: true,
+    condition: obj => !obj.type || obj.type === 'newestSegmentFirst',
     completions: [
+      { value: 'type', documentation: 'Policy type' },
+      { value: 'priorityDatasource', documentation: 'Datasource to prioritize 
for compaction' },
+    ],
+  },
+  // compactionPolicy object properties (mostFragmentedFirst)
+  {
+    path: '$.compactionPolicy',
+    isObject: true,
+    condition: obj => obj.type === 'mostFragmentedFirst',
+    completions: [
+      { value: 'type', documentation: 'Policy type' },
+      { value: 'priorityDatasource', documentation: 'Datasource to prioritize 
for compaction' },
       {
-        value: 'type',
-        documentation: 'Policy type (currently only newestSegmentFirst is 
supported)',
+        value: 'minUncompactedCount',
+        documentation:
+          'Minimum number of uncompacted segments in an interval to be 
eligible for compaction (default: 100)',
+      },
+      {
+        value: 'minUncompactedBytes',
+        documentation:
+          'Minimum total bytes of uncompacted segments in an interval 
(default: 10 MiB)',
+      },
+      {
+        value: 'maxAverageUncompactedBytesPerSegment',
+        documentation:
+          'Maximum average size of uncompacted segments eligible for 
compaction (default: 2 GiB)',
+      },
+      {
+        value: 'minUncompactedBytesPercentForFullCompaction',
+        documentation:
+          'Threshold percentage of uncompacted bytes below which minor 
compaction is used (default: 0)',
+      },
+      {
+        value: 'minUncompactedRowsPercentForFullCompaction',
+        documentation:
+          'Threshold percentage of uncompacted rows below which minor 
compaction is used (default: 0)',
       },
-      { value: 'priorityDatasource', documentation: 'Datasource to prioritize 
for compaction' },
     ],
   },
   // compactionPolicy.type values
@@ -96,6 +129,11 @@ export const COMPACTION_DYNAMIC_CONFIG_COMPLETIONS: 
JsonCompletionRule[] = [
         value: 'newestSegmentFirst',
         documentation: 'Prioritizes segments with more recent intervals for 
compaction',
       },
+      {
+        value: 'mostFragmentedFirst',
+        documentation:
+          'Experimental: Prioritizes intervals with the largest number of 
small uncompacted segments',
+      },
     ],
   },
   // useSupervisors values
diff --git 
a/web-console/src/druid-models/compaction-dynamic-config/compaction-dynamic-config.tsx
 
b/web-console/src/druid-models/compaction-dynamic-config/compaction-dynamic-config.tsx
index 7d3c766c8aa..061ece15246 100644
--- 
a/web-console/src/druid-models/compaction-dynamic-config/compaction-dynamic-config.tsx
+++ 
b/web-console/src/druid-models/compaction-dynamic-config/compaction-dynamic-config.tsx
@@ -19,12 +19,24 @@
 import { Code } from '@blueprintjs/core';
 
 import type { Field } from '../../components';
-import { deepGet } from '../../utils';
+import { deepGet, deepSet } from '../../utils';
+
+export type CompactionPolicy =
+  | { type: 'newestSegmentFirst'; priorityDatasource?: string | null }
+  | {
+      type: 'mostFragmentedFirst';
+      priorityDatasource?: string | null;
+      minUncompactedCount?: number;
+      minUncompactedBytes?: number;
+      maxAverageUncompactedBytesPerSegment?: number;
+      minUncompactedBytesPercentForFullCompaction?: number;
+      minUncompactedRowsPercentForFullCompaction?: number;
+    };
 
 export interface CompactionDynamicConfig {
   compactionTaskSlotRatio: number;
   maxCompactionTaskSlots: number;
-  compactionPolicy: { type: 'newestSegmentFirst'; priorityDatasource?: string 
| null };
+  compactionPolicy: CompactionPolicy;
   useSupervisors: boolean;
   engine: 'native' | 'msq';
   storeCompactionStatePerSegment: boolean;
@@ -74,18 +86,36 @@ export const COMPACTION_DYNAMIC_CONFIG_FIELDS: 
Field<CompactionDynamicConfig>[]
     name: 'compactionPolicy.type',
     label: 'Compaction search policy',
     type: 'string',
-    suggestions: ['newestSegmentFirst'],
+    suggestions: ['newestSegmentFirst', 'mostFragmentedFirst'],
     info: (
       <>
-        Currently, the only supported policy is 
<Code>newestSegmentFirst</Code>, which prioritizes
-        segments with more recent intervals for compaction.
+        <p>
+          <Code>newestSegmentFirst</Code> prioritizes segments with more 
recent intervals for
+          compaction.
+        </p>
+        <p>
+          <Code>mostFragmentedFirst</Code> (experimental) prioritizes 
intervals with the largest
+          number of small uncompacted segments, favoring cluster stability 
over query performance on
+          newer intervals.
+        </p>
       </>
     ),
+    adjustment: config => {
+      const policyType = deepGet(config, 'compactionPolicy.type');
+      const priorityDatasource = deepGet(config, 
'compactionPolicy.priorityDatasource');
+      const newPolicy: Record<string, any> = { type: policyType };
+      if (priorityDatasource) {
+        newPolicy.priorityDatasource = priorityDatasource;
+      }
+      return deepSet(config, 'compactionPolicy', newPolicy);
+    },
   },
   {
     name: 'compactionPolicy.priorityDatasource',
     type: 'string',
-    defined: config => deepGet(config, 'compactionPolicy.type') === 
'newestSegmentFirst',
+    defined: config =>
+      deepGet(config, 'compactionPolicy.type') === 'newestSegmentFirst' ||
+      deepGet(config, 'compactionPolicy.type') === 'mostFragmentedFirst',
     placeholder: '(none)',
     info: (
       <>
@@ -95,6 +125,79 @@ export const COMPACTION_DYNAMIC_CONFIG_FIELDS: 
Field<CompactionDynamicConfig>[]
       </>
     ),
   },
+  {
+    name: 'compactionPolicy.minUncompactedCount',
+    label: 'Min uncompacted segment count',
+    type: 'number',
+    defaultValue: 100,
+    min: 1,
+    defined: config => deepGet(config, 'compactionPolicy.type') === 
'mostFragmentedFirst',
+    info: (
+      <>
+        Minimum number of uncompacted segments that must be present in an 
interval to make it
+        eligible for compaction.
+      </>
+    ),
+  },
+  {
+    name: 'compactionPolicy.minUncompactedBytes',
+    label: 'Min uncompacted bytes',
+    type: 'size-bytes',
+    defaultValue: 10485760,
+    defined: config => deepGet(config, 'compactionPolicy.type') === 
'mostFragmentedFirst',
+    info: (
+      <>
+        Minimum total bytes of uncompacted segments that must be present in an 
interval to make it
+        eligible for compaction. Default: 10 MiB.
+      </>
+    ),
+  },
+  {
+    name: 'compactionPolicy.maxAverageUncompactedBytesPerSegment',
+    label: 'Max avg uncompacted segment size',
+    type: 'size-bytes',
+    defaultValue: 2147483648,
+    defined: config => deepGet(config, 'compactionPolicy.type') === 
'mostFragmentedFirst',
+    info: (
+      <>
+        Maximum average size of uncompacted segments in an interval eligible 
for compaction.
+        Intervals where the average uncompacted segment is larger than this 
are skipped. Default: 2
+        GiB.
+      </>
+    ),
+  },
+  {
+    name: 'compactionPolicy.minUncompactedBytesPercentForFullCompaction',
+    label: 'Min uncompacted bytes % for full compaction',
+    type: 'number',
+    defaultValue: 0,
+    min: 0,
+    max: 99,
+    defined: config => deepGet(config, 'compactionPolicy.type') === 
'mostFragmentedFirst',
+    info: (
+      <>
+        Threshold percentage of uncompacted bytes to total bytes. When the 
ratio of uncompacted
+        bytes falls below this threshold, minor compaction is used instead of 
full compaction. Set
+        to 0 (default) to always use full compaction.
+      </>
+    ),
+  },
+  {
+    name: 'compactionPolicy.minUncompactedRowsPercentForFullCompaction',
+    label: 'Min uncompacted rows % for full compaction',
+    type: 'number',
+    defaultValue: 0,
+    min: 0,
+    max: 99,
+    defined: config => deepGet(config, 'compactionPolicy.type') === 
'mostFragmentedFirst',
+    info: (
+      <>
+        Threshold percentage of uncompacted rows to total rows. When the ratio 
of uncompacted rows
+        falls below this threshold, minor compaction is used instead of full 
compaction. Set to 0
+        (default) to always use full compaction.
+      </>
+    ),
+  },
   {
     name: 'storeCompactionStatePerSegment',
     label: 'Legacy: Persist last compaction state in segments',


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to