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

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


The following commit(s) were added to refs/heads/master by this push:
     new 41048fb57a9 HDDS-12563. Cache and reuse ContainerID object (#10642)
41048fb57a9 is described below

commit 41048fb57a9fb0a12688b5bf56fc004afdccf461
Author: Tsz-Wo Nicholas Sze <[email protected]>
AuthorDate: Thu Jul 2 10:24:03 2026 -0700

    HDDS-12563. Cache and reuse ContainerID object (#10642)
---
 .../hadoop/hdds/scm/container/ContainerID.java     |  15 ++-
 .../hadoop/hdds/scm/container/TestContainerID.java | 133 +++++++++++++++++++++
 .../org/apache/ratis/util/RatisUtilTestUtil.java   |  30 +++++
 3 files changed, 176 insertions(+), 2 deletions(-)

diff --git 
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerID.java
 
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerID.java
index ad7dec5fc4c..61ae9517069 100644
--- 
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerID.java
+++ 
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerID.java
@@ -27,6 +27,7 @@
 import org.apache.hadoop.hdds.utils.db.DelegatedCodec;
 import org.apache.hadoop.hdds.utils.db.LongCodec;
 import org.apache.ratis.util.MemoizedSupplier;
+import org.apache.ratis.util.WeakValueCache;
 
 /**
  * Container ID is an integer that is a value between 1..MAX_CONTAINER ID.
@@ -42,7 +43,9 @@ public final class ContainerID implements 
Comparable<ContainerID> {
       LongCodec.get(), ContainerID::valueOf, c -> c.id,
       ContainerID.class, DelegatedCodec.CopyType.SHALLOW);
 
-  public static final ContainerID MIN = ContainerID.valueOf(0);
+  public static final ContainerID MIN = new ContainerID(0);
+  private static final WeakValueCache<Long, ContainerID> CACHE
+      = new WeakValueCache<>("containerId", ContainerID::new);
 
   private final long id;
   private final Supplier<HddsProtos.ContainerID> proto;
@@ -71,7 +74,11 @@ private ContainerID(long id) {
    * @return ContainerID.
    */
   public static ContainerID valueOf(final long containerID) {
-    return new ContainerID(containerID);
+    return CACHE.getOrCreate(containerID);
+  }
+
+  static WeakValueCache<Long, ContainerID> getCacheForTesting() {
+    return CACHE;
   }
 
   /**
@@ -87,6 +94,10 @@ public long getId() {
     return id;
   }
 
+  public long getIdForTesting() {
+    return id;
+  }
+
   public static byte[] getBytes(long id) {
     return LongCodec.get().toPersistedFormat(id);
   }
diff --git 
a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/scm/container/TestContainerID.java
 
b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/scm/container/TestContainerID.java
new file mode 100644
index 00000000000..73ce557bd72
--- /dev/null
+++ 
b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/scm/container/TestContainerID.java
@@ -0,0 +1,133 @@
+/*
+ * 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.hdds.scm.container;
+
+import static org.apache.hadoop.hdds.utils.db.CodecTestUtil.gc;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import org.apache.ratis.util.JavaUtils;
+import org.apache.ratis.util.RatisUtilTestUtil;
+import org.apache.ratis.util.TimeDuration;
+import org.apache.ratis.util.WeakValueCache;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Test {@link ContainerID}. */
+public final class TestContainerID {
+  private static final Logger LOG = 
LoggerFactory.getLogger(TestContainerID.class);
+
+  private static final WeakValueCache<Long, ContainerID> CACHE = 
ContainerID.getCacheForTesting();
+
+  static String dumpCache() {
+    final List<ContainerID> values = RatisUtilTestUtil.getValues(CACHE);
+    values.sort(Comparator.comparing(ContainerID::getIdForTesting));
+    String header = CACHE + ": " + values.size();
+    System.out.println(header);
+    System.out.println("  " + values);
+    return header;
+  }
+
+  static void assertCache(IDs expectedIDs) {
+    final List<ContainerID> computed = RatisUtilTestUtil.getValues(CACHE);
+    computed.sort(Comparator.comparing(ContainerID::getIdForTesting));
+
+    final List<ContainerID> expected = expectedIDs.getIds();
+    expected.sort(Comparator.comparing(ContainerID::getIdForTesting));
+
+    assertEquals(expected, computed, TestContainerID::dumpCache);
+  }
+
+  void assertCacheSizeWithGC(IDs expectedIDs) throws Exception {
+    JavaUtils.attempt(() -> {
+      gc();
+      assertCache(expectedIDs);
+    }, 5, TimeDuration.valueOf(100, TimeUnit.MILLISECONDS), 
"assertCacheSizeWithGC", LOG);
+  }
+
+  static class IDs {
+    private final List<ContainerID> ids = new LinkedList<>();
+
+    List<ContainerID> getIds() {
+      return new ArrayList<>(ids);
+    }
+
+    int size() {
+      return ids.size();
+    }
+
+    ContainerID allocate() {
+      final ContainerID id = 
ContainerID.valueOf(ThreadLocalRandom.current().nextLong(Long.MAX_VALUE));
+      LOG.info("allocate {}", id);
+      ids.add(id);
+      return id;
+    }
+
+    void release() {
+      final int r = ThreadLocalRandom.current().nextInt(size());
+      final ContainerID removed = ids.remove(r);
+      LOG.info("release {}", removed);
+    }
+  }
+
+  @Test
+  public void testCaching() throws Exception {
+    final int n = 100;
+    final IDs ids = new IDs();
+    assertEquals(0, ids.size());
+    assertCache(ids);
+
+    for (int i = 0; i < n; i++) {
+      final ContainerID id = ids.allocate();
+      assertSame(id, ContainerID.valueOf(id.getIdForTesting()));
+      assertCache(ids);
+    }
+
+    for (int i = 0; i < n / 2; i++) {
+      ids.release();
+      if (ThreadLocalRandom.current().nextInt(10) == 0) {
+        assertCacheSizeWithGC(ids);
+      }
+    }
+    assertCacheSizeWithGC(ids);
+
+    for (int i = 0; i < n / 2; i++) {
+      final ContainerID id = ids.allocate();
+      assertSame(id, ContainerID.valueOf(id.getIdForTesting()));
+      assertCache(ids);
+    }
+
+
+    for (int i = 0; i < n; i++) {
+      ids.release();
+      if (ThreadLocalRandom.current().nextInt(10) == 0) {
+        assertCacheSizeWithGC(ids);
+      }
+    }
+    assertCacheSizeWithGC(ids);
+
+    assertEquals(0, ids.size());
+  }
+}
diff --git 
a/hadoop-hdds/common/src/test/java/org/apache/ratis/util/RatisUtilTestUtil.java 
b/hadoop-hdds/common/src/test/java/org/apache/ratis/util/RatisUtilTestUtil.java
new file mode 100644
index 00000000000..38ac252c7d0
--- /dev/null
+++ 
b/hadoop-hdds/common/src/test/java/org/apache/ratis/util/RatisUtilTestUtil.java
@@ -0,0 +1,30 @@
+/*
+ * 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.ratis.util;
+
+import java.util.List;
+
+/** Test util for the {@link org.apache.ratis.util} package. */
+public final class RatisUtilTestUtil {
+
+  private RatisUtilTestUtil() { }
+
+  public static <K, V> List<V> getValues(WeakValueCache<K, V> cache) {
+    return cache.getValues();
+  }
+}


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

Reply via email to