jtuglu1 commented on code in PR #19501:
URL: https://github.com/apache/druid/pull/19501#discussion_r3439837809


##########
processing/src/main/java/org/apache/druid/common/config/JacksonConfigManager.java:
##########
@@ -127,6 +128,112 @@ public <T> SetResult set(
     return configManager.set(key, configSerde, oldValue, newValue);
   }
 
+  @Nullable
+  public byte[] getCurrentBytes(String key)
+  {
+    return configManager.getCurrentBytes(key);
+  }
+
+  public boolean isCompareAndSwapEnabled()
+  {
+    return configManager.isCompareAndSwapEnabled();
+  }
+
+  /**
+   * Set the config, optionally guarded by an {@code If-Match}-style
+   * precondition. When {@code ifMatchEtag} is {@code null}, behaves like
+   * {@link #set(String, Object, AuditInfo)}. Otherwise the write only commits
+   * if the currently stored bytes hash to {@code ifMatchEtag}; on mismatch the
+   * result reports {@link SetResult#isPreconditionFailed() 
preconditionFailed}.
+   *
+   * <p>The precondition is enforced via metadata-store CAS, so conditional
+   * writes require {@code druid.manager.config.enableCompareAndSwap} to be
+   * true (the default). With CAS disabled, {@code If-Match} writes fail as a
+   * precondition failure instead of silently degrading to last-writer-wins.
+   */
+  public <T> SetResult setIfMatch(
+      String key,
+      @Nullable String ifMatchEtag,
+      T newValue,
+      AuditInfo auditInfo
+  )
+  {
+    if (newValue == null) {
+      return SetResult.failure(new IllegalArgumentException("input obj is 
null"));
+    }
+    if (ifMatchEtag == null) {
+      return set(key, newValue, auditInfo);
+    }
+    if (!configManager.isCompareAndSwapEnabled()) {
+      return SetResult.preconditionFailed(
+          new IllegalStateException(
+              "If-Match requires druid.manager.config.enableCompareAndSwap to 
be enabled for key[" + key + "]"
+          )
+      );
+    }
+    final byte[] currentBytes = configManager.getCurrentBytes(key);
+    if (!ConfigEtag.matches(ifMatchEtag, currentBytes)) {
+      return SetResult.preconditionFailed(
+          new IllegalStateException("If-Match precondition failed for key[" + 
key + "]")
+      );
+    }
+    final SetResult result = set(key, currentBytes, newValue, auditInfo);
+    // Retryable CAS failure here = concurrent writer between our read and CAS;
+    // surface as precondition failed since the caller asked us to reject that.
+    if (!result.isOk() && result.isRetryable()) {
+      return SetResult.preconditionFailed(
+          new IllegalStateException("If-Match precondition failed (concurrent 
update) for key[" + key + "]")
+      );
+    }

Review Comment:
   Done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to