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

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


The following commit(s) were added to refs/heads/master by this push:
     new 99186095f12c [HUDI-9742] Add lock release metrics (#13757)
99186095f12c is described below

commit 99186095f12cbc9eddd1e9a00d0eda5f3c8aea3a
Author: Alex R <[email protected]>
AuthorDate: Sun Aug 24 19:47:39 2025 -0700

    [HUDI-9742] Add lock release metrics (#13757)
---
 .../hudi/client/transaction/lock/LockManager.java  |  1 +
 .../lock/metrics/HoodieLockMetrics.java            | 10 ++-
 .../client/transaction/TestHoodieLockMetrics.java  | 85 ++++++++++++++++++++++
 3 files changed, 95 insertions(+), 1 deletion(-)

diff --git 
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/lock/LockManager.java
 
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/lock/LockManager.java
index 57ed6df45afb..b1be2ab30783 100644
--- 
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/lock/LockManager.java
+++ 
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/lock/LockManager.java
@@ -101,6 +101,7 @@ public class LockManager implements Serializable, 
AutoCloseable {
     } catch (HoodieException e) {
       LOG.error(String.format("Exception encountered when updating lock 
metrics: %s", e));
     }
+    metrics.updateLockReleaseSuccessMetric();
     close();
   }
 
diff --git 
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/lock/metrics/HoodieLockMetrics.java
 
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/lock/metrics/HoodieLockMetrics.java
index 924cef8bf917..29bacad81767 100644
--- 
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/lock/metrics/HoodieLockMetrics.java
+++ 
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/lock/metrics/HoodieLockMetrics.java
@@ -39,6 +39,7 @@ public class HoodieLockMetrics {
   public static final String LOCK_ACQUIRE_ATTEMPTS_COUNTER_NAME = 
"lock.acquire.attempts";
   public static final String LOCK_ACQUIRE_SUCCESS_COUNTER_NAME = 
"lock.acquire.success";
   public static final String LOCK_ACQUIRE_FAILURES_COUNTER_NAME = 
"lock.acquire.failure";
+  public static final String LOCK_RELEASE_SUCCESS_COUNTER_NAME = 
"lock.release.success";
   public static final String LOCK_ACQUIRE_DURATION_TIMER_NAME = 
"lock.acquire.duration";
   public static final String LOCK_REQUEST_LATENCY_TIMER_NAME = 
"lock.request.latency";
   private final HoodieWriteConfig writeConfig;
@@ -49,6 +50,7 @@ public class HoodieLockMetrics {
   private transient Counter lockAttempts;
   private transient Counter successfulLockAttempts;
   private transient Counter failedLockAttempts;
+  private transient Counter lockReleaseSuccess;
   private transient Timer lockDuration;
   private transient Timer lockApiRequestDuration;
   private static final Object REGISTRY_LOCK = new Object();
@@ -65,7 +67,7 @@ public class HoodieLockMetrics {
       lockAttempts = 
registry.counter(getMetricsName(LOCK_ACQUIRE_ATTEMPTS_COUNTER_NAME));
       successfulLockAttempts = 
registry.counter(getMetricsName(LOCK_ACQUIRE_SUCCESS_COUNTER_NAME));
       failedLockAttempts = 
registry.counter(getMetricsName(LOCK_ACQUIRE_FAILURES_COUNTER_NAME));
-
+      lockReleaseSuccess = 
registry.counter(getMetricsName(LOCK_RELEASE_SUCCESS_COUNTER_NAME));
       lockDuration = createTimerForMetrics(registry, 
LOCK_ACQUIRE_DURATION_TIMER_NAME);
       lockApiRequestDuration = createTimerForMetrics(registry, 
LOCK_REQUEST_LATENCY_TIMER_NAME);
     }
@@ -125,4 +127,10 @@ public class HoodieLockMetrics {
       updateMetric(lockDurationTimer, lockDuration, "held");
     }
   }
+
+  public void updateLockReleaseSuccessMetric() {
+    if (isMetricsEnabled) {
+      lockReleaseSuccess.inc();
+    }
+  }
 }
diff --git 
a/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/client/transaction/TestHoodieLockMetrics.java
 
b/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/client/transaction/TestHoodieLockMetrics.java
index e4260f4d4e3e..0cf1de5653a2 100644
--- 
a/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/client/transaction/TestHoodieLockMetrics.java
+++ 
b/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/client/transaction/TestHoodieLockMetrics.java
@@ -19,15 +19,20 @@
 
 package org.apache.hudi.client.transaction;
 
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.MetricRegistry;
 import org.apache.hudi.client.transaction.lock.metrics.HoodieLockMetrics;
 import org.apache.hudi.config.HoodieWriteConfig;
 import org.apache.hudi.config.metrics.HoodieMetricsConfig;
 import org.apache.hudi.metrics.MetricsReporterType;
 import org.apache.hudi.storage.HoodieStorage;
+import org.apache.hudi.metrics.Metrics;
 
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.mockito.Mockito.mock;
 
 public class TestHoodieLockMetrics {
@@ -67,4 +72,84 @@ public class TestHoodieLockMetrics {
     assertDoesNotThrow(lockMetrics::updateLockAcquiredMetric);
   }
 
+  @Test
+  public void testLockReleaseSuccessMetric() {
+    // Test that lock release success metric is properly tracked
+    HoodieStorage storage = mock(HoodieStorage.class);
+    HoodieMetricsConfig metricsConfig = 
HoodieMetricsConfig.newBuilder().withPath("/test")
+        
.withReporterType(MetricsReporterType.INMEMORY.name()).withLockingMetrics(true).build();
+    HoodieWriteConfig writeConfig = HoodieWriteConfig.newBuilder()
+        .forTable("testTable").withPath("/test/path")
+        .withMetricsConfig(metricsConfig)
+        .build();
+    HoodieLockMetrics lockMetrics = new HoodieLockMetrics(writeConfig, 
storage);
+
+    // Get the metrics registry to verify counter values
+    Metrics metrics = Metrics.getInstance(metricsConfig, storage);
+    MetricRegistry registry = metrics.getRegistry();
+
+    // Verify the lock release success counter exists
+    String metricName = writeConfig.getMetricReporterMetricsNamePrefix() + "." 
+ HoodieLockMetrics.LOCK_RELEASE_SUCCESS_COUNTER_NAME;
+    Counter lockReleaseSuccessCounter = registry.getCounters().get(metricName);
+    assertNotNull(lockReleaseSuccessCounter, "Lock release success counter 
should exist");
+    
+    long initialCount = lockReleaseSuccessCounter.getCount();
+
+    // Simulate successful lock release
+    lockMetrics.updateLockReleaseSuccessMetric();
+    assertEquals(initialCount + 1, lockReleaseSuccessCounter.getCount(), "Lock 
release success counter should increment by 1");
+
+    // Simulate multiple successful lock releases
+    lockMetrics.updateLockReleaseSuccessMetric();
+    lockMetrics.updateLockReleaseSuccessMetric();
+    assertEquals(initialCount + 3, lockReleaseSuccessCounter.getCount(), "Lock 
release success counter should increment by 3 total");
+  }
+
+  @Test
+  public void testLockLifecycleWithReleaseSuccess() {
+    // Test complete lock lifecycle including acquisition and successful 
release
+    HoodieStorage storage = mock(HoodieStorage.class);
+    HoodieMetricsConfig metricsConfig = 
HoodieMetricsConfig.newBuilder().withPath("/test")
+        
.withReporterType(MetricsReporterType.INMEMORY.name()).withLockingMetrics(true).build();
+    HoodieWriteConfig writeConfig = HoodieWriteConfig.newBuilder()
+        .forTable("testTable").withPath("/test/path")
+        .withMetricsConfig(metricsConfig)
+        .build();
+    HoodieLockMetrics lockMetrics = new HoodieLockMetrics(writeConfig, 
storage);
+
+    // Get the metrics registry to verify counter values
+    Metrics metrics = Metrics.getInstance(metricsConfig, storage);
+    MetricRegistry registry = metrics.getRegistry();
+
+    String acquireMetricName = 
writeConfig.getMetricReporterMetricsNamePrefix() + "." + 
HoodieLockMetrics.LOCK_ACQUIRE_SUCCESS_COUNTER_NAME;
+    String releaseMetricName = 
writeConfig.getMetricReporterMetricsNamePrefix() + "." + 
HoodieLockMetrics.LOCK_RELEASE_SUCCESS_COUNTER_NAME;
+    Counter lockAcquiredCounter = 
registry.getCounters().get(acquireMetricName);
+    Counter lockReleaseSuccessCounter = 
registry.getCounters().get(releaseMetricName);
+    
+    long initialAcquireCount = lockAcquiredCounter.getCount();
+    long initialReleaseCount = lockReleaseSuccessCounter.getCount();
+    
+    // Simulate complete lock lifecycle
+    lockMetrics.startLockApiTimerContext();
+    lockMetrics.updateLockAcquiredMetric();
+    assertEquals(initialAcquireCount + 1, lockAcquiredCounter.getCount(), 
"Lock acquired counter should increment by 1");
+    assertEquals(initialReleaseCount, lockReleaseSuccessCounter.getCount(), 
"Lock release success counter should not change yet");
+
+    // Now release the lock successfully
+    lockMetrics.updateLockReleaseSuccessMetric();
+    lockMetrics.updateLockHeldTimerMetrics();
+    assertEquals(initialAcquireCount + 1, lockAcquiredCounter.getCount(), 
"Lock acquired counter should still be incremented by 1");
+    assertEquals(initialReleaseCount + 1, 
lockReleaseSuccessCounter.getCount(), "Lock release success counter should 
increment by 1");
+
+    // Verify metrics balance for multiple cycles
+    for (int i = 0; i < 5; i++) {
+      lockMetrics.startLockApiTimerContext();
+      lockMetrics.updateLockAcquiredMetric();
+      lockMetrics.updateLockReleaseSuccessMetric();
+      lockMetrics.updateLockHeldTimerMetrics();
+    }
+    
+    assertEquals(initialAcquireCount + 6, lockAcquiredCounter.getCount(), 
"Lock acquired counter should increment by 6 total");
+    assertEquals(initialReleaseCount + 6, 
lockReleaseSuccessCounter.getCount(), "Lock release success counter should 
increment by 6 total");
+  }
 }

Reply via email to