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


##########
processing/src/main/java/org/apache/druid/common/config/JacksonConfigManager.java:
##########
@@ -127,6 +127,66 @@ 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);

Review Comment:
   [P1] Build conditional partial updates from the CAS snapshot
   
   setIfMatch reads the bytes used for If-Match validation and CAS after 
callers have already built newValue. That is safe for full replacements, but 
the new Coordinator/Broker/K8s partial-update endpoints merge request fields 
with a watched config object before calling this method. If the watcher 
advances between that merge and this read, an If-Match for snapshot B can pass 
and CAS B -> newValue(A + patch), dropping fields introduced in B while 
returning success. Conditional partial writes need a transform-style path that 
reads bytes, validates the ETag, deserializes those same bytes, applies the 
patch, and CASes the same byte snapshot.



-- 
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