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

anujmodi pushed a commit to branch branch-3.4
in repository https://gitbox.apache.org/repos/asf/hadoop.git


The following commit(s) were added to refs/heads/branch-3.4 by this push:
     new 0358b900d1e HADOOP-19280. [ABFS] Initialize client timer only if 
metric collection is enabled (#7307)
0358b900d1e is described below

commit 0358b900d1e61c0d27e3c34f3e1ff83bdd7b3cc9
Author: Manish Bhatt <52626736+bhattmanis...@users.noreply.github.com>
AuthorDate: Wed Jan 22 06:14:12 2025 +0000

    HADOOP-19280. [ABFS] Initialize client timer only if metric collection is 
enabled (#7307)
    
    Contributed by Manish Bhatt
---
 .../hadoop/fs/azurebfs/services/AbfsClient.java    |  18 ++-
 .../fs/azurebfs/services/TestAbfsClient.java       | 141 +++++++++++++++++++++
 2 files changed, 155 insertions(+), 4 deletions(-)

diff --git 
a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsClient.java
 
b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsClient.java
index 0eb23bd19ed..2119b1b30c3 100644
--- 
a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsClient.java
+++ 
b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsClient.java
@@ -136,6 +136,7 @@
 public abstract class AbfsClient implements Closeable {
   public static final Logger LOG = LoggerFactory.getLogger(AbfsClient.class);
   public static final String HUNDRED_CONTINUE_USER_AGENT = SINGLE_WHITE_SPACE 
+ HUNDRED_CONTINUE + SEMICOLON;
+  public static final String ABFS_CLIENT_TIMER_THREAD_NAME = 
"abfs-timer-client";
 
   private final URL baseUrl;
   private final SharedKeyCredentials sharedKeyCredentials;
@@ -154,7 +155,7 @@ public abstract class AbfsClient implements Closeable {
   private AccessTokenProvider tokenProvider;
   private SASTokenProvider sasTokenProvider;
   private final AbfsCounters abfsCounters;
-  private final Timer timer;
+  private Timer timer;
   private final String abfsMetricUrl;
   private boolean isMetricCollectionEnabled = false;
   private final MetricFormat metricFormat;
@@ -263,9 +264,9 @@ private AbfsClient(final URL baseUrl,
         throw new IOException("Exception while initializing metric credentials 
" + e);
       }
     }
-    this.timer = new Timer(
-        "abfs-timer-client", true);
     if (isMetricCollectionEnabled) {
+      this.timer = new Timer(
+              ABFS_CLIENT_TIMER_THREAD_NAME, true);
       timer.schedule(new TimerTaskImpl(),
           metricIdlePeriod,
           metricIdlePeriod);
@@ -297,6 +298,10 @@ public AbfsClient(final URL baseUrl, final 
SharedKeyCredentials sharedKeyCredent
 
   @Override
   public void close() throws IOException {
+    if (isMetricCollectionEnabled && runningTimerTask != null) {
+      runningTimerTask.cancel();
+      timer.cancel();
+    }
     if (keepAliveCache != null) {
       keepAliveCache.close();
     }
@@ -1425,7 +1430,7 @@ private TracingContext getMetricTracingContext() {
   boolean timerOrchestrator(TimerFunctionality timerFunctionality, TimerTask 
timerTask) {
     switch (timerFunctionality) {
       case RESUME:
-        if (isMetricCollectionStopped.get()) {
+        if (isMetricCollectionEnabled && isMetricCollectionStopped.get()) {
           synchronized (this) {
             if (isMetricCollectionStopped.get()) {
               resumeTimer();
@@ -1604,6 +1609,11 @@ KeepAliveCache getKeepAliveCache() {
     return keepAliveCache;
   }
 
+  @VisibleForTesting
+  protected Timer getTimer() {
+    return timer;
+  }
+
   protected String getUserAgent() {
     return userAgent;
   }
diff --git 
a/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/services/TestAbfsClient.java
 
b/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/services/TestAbfsClient.java
new file mode 100644
index 00000000000..e8ab4291b32
--- /dev/null
+++ 
b/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/services/TestAbfsClient.java
@@ -0,0 +1,141 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.fs.azurebfs.services;
+
+import java.net.URI;
+import java.net.URL;
+import java.util.Map;
+
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.azurebfs.AbfsConfiguration;
+import org.apache.hadoop.fs.azurebfs.AbfsCountersImpl;
+import org.apache.hadoop.fs.azurebfs.oauth2.AccessTokenProvider;
+import org.apache.hadoop.fs.azurebfs.utils.Base64;
+import org.apache.hadoop.fs.azurebfs.utils.MetricFormat;
+
+import static 
org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_METRIC_ACCOUNT_KEY;
+import static 
org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_METRIC_ACCOUNT_NAME;
+import static 
org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_METRIC_FORMAT;
+import static 
org.apache.hadoop.fs.azurebfs.services.AbfsClient.ABFS_CLIENT_TIMER_THREAD_NAME;
+
+/**
+ * Unit test cases for the AbfsClient class.
+ */
+public class TestAbfsClient {
+    private static final String ACCOUNT_NAME = 
"bogusAccountName.dfs.core.windows.net";
+    private static final String ACCOUNT_KEY = "testKey";
+    private static final long SLEEP_DURATION_MS = 500;
+
+    /**
+     * Test the initialization of the AbfsClient timer when metric collection 
is disabled.
+     * In case of metric collection being disabled, the timer should not be 
initialized.
+     * Asserting that the timer is null and the abfs-timer-client thread is 
not running.
+     */
+    @Test
+    public void testTimerInitializationWithoutMetricCollection() throws 
Exception {
+        final Configuration configuration = new Configuration();
+        AbfsConfiguration abfsConfiguration = new 
AbfsConfiguration(configuration, ACCOUNT_NAME);
+
+        AbfsCounters abfsCounters = Mockito.spy(new AbfsCountersImpl(new 
URI("abcd")));
+        AbfsClientContext abfsClientContext = new 
AbfsClientContextBuilder().withAbfsCounters(abfsCounters).build();
+
+        // Get an instance of AbfsClient.
+        AbfsClient client = new AbfsDfsClient(new URL("https://azure.com";),
+                null,
+                abfsConfiguration,
+                (AccessTokenProvider) null,
+                null,
+                abfsClientContext);
+
+        Assertions.assertThat(client.getTimer())
+                .describedAs("Timer should not be initialized")
+                .isNull();
+
+        // Check if a thread with the name "abfs-timer-client" exists
+        Assertions.assertThat(isThreadRunning(ABFS_CLIENT_TIMER_THREAD_NAME))
+                .describedAs("Expected thread 'abfs-timer-client' not found")
+                .isEqualTo(false);
+        client.close();
+    }
+
+    /**
+     * Test the initialization of the AbfsClient timer when metric collection 
is enabled.
+     * In case of metric collection being enabled, the timer should be 
initialized.
+     * Asserting that the timer is not null and the abfs-timer-client thread 
is running.
+     * Also, asserting that the thread is removed after closing the client.
+     */
+    @Test
+    public void testTimerInitializationWithMetricCollection() throws Exception 
{
+        final Configuration configuration = new Configuration();
+        configuration.set(FS_AZURE_METRIC_FORMAT, 
String.valueOf(MetricFormat.INTERNAL_BACKOFF_METRIC_FORMAT));
+        configuration.set(FS_AZURE_METRIC_ACCOUNT_NAME, ACCOUNT_NAME);
+        configuration.set(FS_AZURE_METRIC_ACCOUNT_KEY, 
Base64.encode(ACCOUNT_KEY.getBytes()));
+        AbfsConfiguration abfsConfiguration = new 
AbfsConfiguration(configuration, ACCOUNT_NAME);
+
+        AbfsCounters abfsCounters = Mockito.spy(new AbfsCountersImpl(new 
URI("abcd")));
+        AbfsClientContext abfsClientContext = new 
AbfsClientContextBuilder().withAbfsCounters(abfsCounters).build();
+
+        // Get an instance of AbfsClient.
+        AbfsClient client = new AbfsDfsClient(new URL("https://azure.com";),
+                null,
+                abfsConfiguration,
+                (AccessTokenProvider) null,
+                null,
+                abfsClientContext);
+
+        Assertions.assertThat(client.getTimer())
+                .describedAs("Timer should be initialized")
+                .isNotNull();
+
+        // Check if a thread with the name "abfs-timer-client" exists
+        Assertions.assertThat(isThreadRunning(ABFS_CLIENT_TIMER_THREAD_NAME))
+                .describedAs("Expected thread 'abfs-timer-client' not found")
+                .isEqualTo(true);
+        client.close();
+
+        // Check if the thread is removed after closing the client
+        Thread.sleep(SLEEP_DURATION_MS);
+        Assertions.assertThat(isThreadRunning(ABFS_CLIENT_TIMER_THREAD_NAME))
+                .describedAs("Unexpected thread 'abfs-timer-client' found")
+                .isEqualTo(false);
+    }
+
+    /**
+     * Check if a thread with the specified name is running.
+     *
+     * @param threadName Name of the thread to check
+     * @return true if the thread is running, false otherwise
+     */
+    private boolean isThreadRunning(String threadName) {
+        // Get all threads and their stack traces
+        Map<Thread, StackTraceElement[]> allThreads = 
Thread.getAllStackTraces();
+
+        // Check if any thread has the specified name
+        for (Thread thread : allThreads.keySet()) {
+            if (thread.getName().equals(threadName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscr...@hadoop.apache.org
For additional commands, e-mail: common-commits-h...@hadoop.apache.org

Reply via email to