@@ -97,25 +97,6 @@ public CoordinatorDynamicConfig convertBytesToDynamicConfig(@Nullable byte[] byt
9797 );
9898 }
9999
100- public ConfigManager .SetResult setDynamicConfig (CoordinatorDynamicConfig config , AuditInfo auditInfo )
101- {
102- return setDynamicConfig (config , null , auditInfo );
103- }
104-
105- public ConfigManager .SetResult setDynamicConfig (
106- CoordinatorDynamicConfig config ,
107- @ Nullable String ifMatchEtag ,
108- AuditInfo auditInfo
109- )
110- {
111- return jacksonConfigManager .setIfMatch (
112- CoordinatorDynamicConfig .CONFIG_KEY ,
113- ifMatchEtag ,
114- config ,
115- auditInfo
116- );
117- }
118-
119100 public ConfigManager .SetResult updateDynamicConfig (
120101 UnaryOperator <CoordinatorDynamicConfig > operator ,
121102 @ Nullable String ifMatchEtag ,
@@ -205,14 +186,22 @@ public ConfigManager.SetResult getAndUpdateCompactionConfig(
205186
206187 if (current .equals (updated )) {
207188 return ConfigManager .SetResult .ok ();
208- } else {
209- return jacksonConfigManager .set (
210- DruidCompactionConfig .CONFIG_KEY ,
211- currentBytes ,
212- updated ,
213- auditInfo
189+ }
190+ final ConfigManager .SetResult result = jacksonConfigManager .set (
191+ DruidCompactionConfig .CONFIG_KEY ,
192+ currentBytes ,
193+ updated ,
194+ auditInfo
195+ );
196+ // Under If-Match, a lost CAS means a concurrent writer committed between our
197+ // read and write: the precondition no longer holds, so report it as such
198+ // rather than as a retryable failure (conditional writes must not auto-retry).
199+ if (ifMatchEtag != null && result .isRetryable ()) {
200+ return ConfigManager .SetResult .preconditionFailed (
201+ new IllegalStateException ("If-Match precondition failed (concurrent update) for compaction config" )
214202 );
215203 }
204+ return result ;
216205 }
217206
218207 public DruidCompactionConfig convertBytesToCompactionConfig (@ Nullable byte [] bytes )
@@ -257,14 +246,6 @@ public boolean updateCompactionTaskSlots(
257246 return updateConfigHelper (operator , ifMatchEtag , auditInfo );
258247 }
259248
260- public boolean updateClusterCompactionConfig (
261- ClusterCompactionConfig config ,
262- AuditInfo auditInfo
263- )
264- {
265- return updateClusterCompactionConfig (config , null , auditInfo );
266- }
267-
268249 public boolean updateClusterCompactionConfig (
269250 ClusterCompactionConfig config ,
270251 @ Nullable String ifMatchEtag ,
@@ -380,17 +361,18 @@ private boolean updateConfigHelper(
380361 AuditInfo auditInfo
381362 )
382363 {
383- int attemps = 0 ;
364+ int attempts = 0 ;
384365 ConfigManager .SetResult setResult = null ;
385- // When the caller has supplied an If-Match precondition, do not retry on CAS failure.
386- final int maxAttempts = ifMatchEtag != null ? 1 : MAX_UPDATE_RETRIES ;
366+ // Only an unconditional write can be retried: getAndUpdateCompactionConfig converts a lost
367+ // CAS under If-Match into a (non-retryable) precondition failure, so conditional writes exit
368+ // this loop on the first attempt rather than silently retrying past the caller's precondition.
387369 try {
388- while (attemps < maxAttempts ) {
370+ while (attempts < MAX_UPDATE_RETRIES ) {
389371 setResult = getAndUpdateCompactionConfig (configUpdateOperator , ifMatchEtag , auditInfo );
390372 if (setResult .isOk () || !setResult .isRetryable ()) {
391373 break ;
392374 }
393- attemps ++;
375+ attempts ++;
394376 updateRetryDelay ();
395377 }
396378 }
@@ -409,18 +391,14 @@ private boolean updateConfigHelper(
409391 return true ;
410392 }
411393
412- // With If-Match, a retryable CAS failure means a concurrent writer beat us
413- // between the precondition check and the CAS — surface as 412 too.
414- final boolean preconditionFailed = setResult .isPreconditionFailed ()
415- || (ifMatchEtag != null && setResult .isRetryable ());
416- if (preconditionFailed ) {
394+ // getAndUpdateCompactionConfig already converts a lost CAS under If-Match into
395+ // a precondition failure, so a retryable result here is only a genuine
396+ // (non-conditional) CAS conflict that exhausted its retries.
397+ if (setResult .isPreconditionFailed ()) {
417398 log .info ("If-Match precondition failed on compaction config update" );
418- final String message = setResult .isPreconditionFailed ()
419- ? setResult .getException ().getMessage ()
420- : "If-Match precondition failed (concurrent update) on compaction config" ;
421399 throw DruidException .forPersona (DruidException .Persona .USER )
422400 .ofCategory (DruidException .Category .PRECONDITION_FAILED )
423- .build (message );
401+ .build (setResult . getException (). getMessage () );
424402 }
425403
426404 if (setResult .getException () instanceof NoSuchElementException ) {
0 commit comments