You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2022/02/26 11:58:29 UTC

[httpcomponents-client] branch 5.1.x updated: Optimize ExecSupport.getNextExchangeId() (#352)

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

olegk pushed a commit to branch 5.1.x
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git


The following commit(s) were added to refs/heads/5.1.x by this push:
     new df63087  Optimize ExecSupport.getNextExchangeId() (#352)
df63087 is described below

commit df630878ad863e8c202235c38ac78cbd8ede1059
Author: David Schlosnagle <sc...@gmail.com>
AuthorDate: Sat Feb 26 06:45:18 2022 -0500

    Optimize ExecSupport.getNextExchangeId() (#352)
---
 .../apache/hc/client5/http/impl/ExecSupport.java   |   9 +-
 .../client5/http/impl/PrefixedIncrementingId.java  | 109 +++++++++++++++++++++
 .../io/PoolingHttpClientConnectionManager.java     |   6 +-
 .../nio/PoolingAsyncClientConnectionManager.java   |   6 +-
 .../hc/client5/http/impl/ExecSupportTest.java}     |  30 +++---
 .../http/impl/PrefixedIncrementingIdTest.java}     |  33 ++++---
 6 files changed, 146 insertions(+), 47 deletions(-)

diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ExecSupport.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ExecSupport.java
index 4d7c5f6..6d9513f 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ExecSupport.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ExecSupport.java
@@ -26,8 +26,6 @@
  */
 package org.apache.hc.client5.http.impl;
 
-import java.util.concurrent.atomic.AtomicLong;
-
 import org.apache.hc.core5.annotation.Internal;
 
 /**
@@ -38,14 +36,13 @@ import org.apache.hc.core5.annotation.Internal;
 @Internal
 public final class ExecSupport {
 
-    private static final AtomicLong COUNT = new AtomicLong(0);
+    private static final PrefixedIncrementingId INCREMENTING_ID = new PrefixedIncrementingId("ex-");
 
     public static long getNextExecNumber() {
-        return COUNT.incrementAndGet();
+        return INCREMENTING_ID.getNextNumber();
     }
 
     public static String getNextExchangeId() {
-        return String.format("ex-%010d", COUNT.incrementAndGet());
+        return INCREMENTING_ID.getNextId();
     }
-
 }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/PrefixedIncrementingId.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/PrefixedIncrementingId.java
new file mode 100644
index 0000000..49e1d2d
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/PrefixedIncrementingId.java
@@ -0,0 +1,109 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.hc.client5.http.impl;
+
+import java.util.concurrent.atomic.AtomicLong;
+import org.apache.hc.core5.annotation.Internal;
+import org.apache.hc.core5.util.Args;
+
+/**
+ * A thread safe incrementing identifier.
+ *
+ * @since 5.1.4
+ */
+@Internal
+public final class PrefixedIncrementingId {
+
+    private final AtomicLong count = new AtomicLong(0);
+    private final String prefix0;
+    private final String prefix1;
+    private final String prefix2;
+    private final String prefix3;
+    private final String prefix4;
+    private final String prefix5;
+    private final String prefix6;
+    private final String prefix7;
+    private final String prefix8;
+    private final String prefix9;
+
+    /**
+     * Creates an incrementing identifier.
+     * @param prefix string prefix for generated IDs
+     */
+    public PrefixedIncrementingId(final String prefix) {
+        this.prefix0 = Args.notNull(prefix, "prefix");
+        this.prefix1 = prefix0 + '0';
+        this.prefix2 = prefix1 + '0';
+        this.prefix3 = prefix2 + '0';
+        this.prefix4 = prefix3 + '0';
+        this.prefix5 = prefix4 + '0';
+        this.prefix6 = prefix5 + '0';
+        this.prefix7 = prefix6 + '0';
+        this.prefix8 = prefix7 + '0';
+        this.prefix9 = prefix8 + '0';
+    }
+
+    public long getNextNumber() {
+        return count.incrementAndGet();
+    }
+
+    public String getNextId() {
+        return createId(count.incrementAndGet());
+    }
+
+    /**
+     * Create an ID from this instance's prefix and zero padded specified value.
+     *
+     * Hand rolled equivalent to `String.format("ex-%010d", value)` optimized to reduce
+     * allocation and CPU overhead.
+     */
+    String createId(final long value) {
+        final String longString = Long.toString(value);
+        switch (longString.length()) {
+            case 1:
+                return prefix9 + longString;
+            case 2:
+                return prefix8 + longString;
+            case 3:
+                return prefix7 + longString;
+            case 4:
+                return prefix6 + longString;
+            case 5:
+                return prefix5 + longString;
+            case 6:
+                return prefix4 + longString;
+            case 7:
+                return prefix3 + longString;
+            case 8:
+                return prefix2 + longString;
+            case 9:
+                return prefix1 + longString;
+            default:
+                return prefix0 + longString;
+        }
+    }
+}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java
index ae90703..c47e476 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java
@@ -32,7 +32,6 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.hc.client5.http.DnsResolver;
@@ -40,6 +39,7 @@ import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.impl.ConnPoolSupport;
 import org.apache.hc.client5.http.impl.ConnectionShutdownException;
+import org.apache.hc.client5.http.impl.PrefixedIncrementingId;
 import org.apache.hc.client5.http.io.ConnectionEndpoint;
 import org.apache.hc.client5.http.io.HttpClientConnectionManager;
 import org.apache.hc.client5.http.io.HttpClientConnectionOperator;
@@ -503,7 +503,7 @@ public class PoolingHttpClientConnectionManager
         this.validateAfterInactivity = validateAfterInactivity;
     }
 
-    private static final AtomicLong COUNT = new AtomicLong(0);
+    private static final PrefixedIncrementingId INCREMENTING_ID = new PrefixedIncrementingId("ep-");
 
     class InternalConnectionEndpoint extends ConnectionEndpoint implements Identifiable {
 
@@ -513,7 +513,7 @@ public class PoolingHttpClientConnectionManager
         InternalConnectionEndpoint(
                 final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry) {
             this.poolEntryRef = new AtomicReference<>(poolEntry);
-            this.id = String.format("ep-%010d", COUNT.getAndIncrement());
+            this.id = INCREMENTING_ID.getNextId();
         }
 
         @Override
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java
index 32617d6..1a3b8c0 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java
@@ -34,7 +34,6 @@ import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.hc.client5.http.DnsResolver;
@@ -42,6 +41,7 @@ import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.impl.ConnPoolSupport;
 import org.apache.hc.client5.http.impl.ConnectionShutdownException;
+import org.apache.hc.client5.http.impl.PrefixedIncrementingId;
 import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
 import org.apache.hc.client5.http.nio.AsyncClientConnectionOperator;
 import org.apache.hc.client5.http.nio.AsyncConnectionEndpoint;
@@ -517,7 +517,7 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
         this.validateAfterInactivity = validateAfterInactivity;
     }
 
-    private static final AtomicLong COUNT = new AtomicLong(0);
+    private static final PrefixedIncrementingId INCREMENTING_ID = new PrefixedIncrementingId("ep-");
 
     class InternalConnectionEndpoint extends AsyncConnectionEndpoint implements Identifiable {
 
@@ -526,7 +526,7 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
 
         InternalConnectionEndpoint(final PoolEntry<HttpRoute, ManagedAsyncClientConnection> poolEntry) {
             this.poolEntryRef = new AtomicReference<>(poolEntry);
-            this.id = String.format("ep-%010d", COUNT.getAndIncrement());
+            this.id = INCREMENTING_ID.getNextId();
         }
 
         @Override
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ExecSupport.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/ExecSupportTest.java
similarity index 72%
copy from httpclient5/src/main/java/org/apache/hc/client5/http/impl/ExecSupport.java
copy to httpclient5/src/test/java/org/apache/hc/client5/http/impl/ExecSupportTest.java
index 4d7c5f6..daf9d1d 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ExecSupport.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/ExecSupportTest.java
@@ -26,26 +26,18 @@
  */
 package org.apache.hc.client5.http.impl;
 
-import java.util.concurrent.atomic.AtomicLong;
+import org.junit.Assert;
+import org.junit.Test;
 
-import org.apache.hc.core5.annotation.Internal;
+public class ExecSupportTest {
 
-/**
- * Request execution support methods.
- *
- * @since 5.0
- */
-@Internal
-public final class ExecSupport {
-
-    private static final AtomicLong COUNT = new AtomicLong(0);
-
-    public static long getNextExecNumber() {
-        return COUNT.incrementAndGet();
+    @Test
+    public void testGetNextExchangeId() {
+        final long base = ExecSupport.getNextExecNumber();
+        for (int i = 1; i <= 1_000_000; i++) {
+            Assert.assertEquals(
+                String.format("ex-%010d", i + base),
+                ExecSupport.getNextExchangeId());
+        }
     }
-
-    public static String getNextExchangeId() {
-        return String.format("ex-%010d", COUNT.incrementAndGet());
-    }
-
 }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ExecSupport.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/PrefixedIncrementingIdTest.java
similarity index 57%
copy from httpclient5/src/main/java/org/apache/hc/client5/http/impl/ExecSupport.java
copy to httpclient5/src/test/java/org/apache/hc/client5/http/impl/PrefixedIncrementingIdTest.java
index 4d7c5f6..5a72d55 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ExecSupport.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/PrefixedIncrementingIdTest.java
@@ -26,26 +26,27 @@
  */
 package org.apache.hc.client5.http.impl;
 
-import java.util.concurrent.atomic.AtomicLong;
+import org.junit.Assert;
+import org.junit.Test;
 
-import org.apache.hc.core5.annotation.Internal;
+public class PrefixedIncrementingIdTest {
 
-/**
- * Request execution support methods.
- *
- * @since 5.0
- */
-@Internal
-public final class ExecSupport {
-
-    private static final AtomicLong COUNT = new AtomicLong(0);
-
-    public static long getNextExecNumber() {
-        return COUNT.incrementAndGet();
+    @Test
+    public void testGetNextId() {
+        final PrefixedIncrementingId testId = new PrefixedIncrementingId("test-");
+        Assert.assertEquals(String.format("test-%010d", 1), testId.getNextId());
+        Assert.assertEquals(String.format("test-%010d", 2), testId.getNextId());
     }
 
-    public static String getNextExchangeId() {
-        return String.format("ex-%010d", COUNT.incrementAndGet());
+    @Test
+    public void testCreateId() {
+        final PrefixedIncrementingId exchangeId = new PrefixedIncrementingId("ex-");
+        Assert.assertEquals(String.format("ex-%010d", 0), exchangeId.createId(0));
+        for (long i = 1; i <= 100_000_000L; i *= 10) {
+            Assert.assertEquals(String.format("ex-%010d", i - 1), exchangeId.createId(i - 1));
+            Assert.assertEquals(String.format("ex-%010d", i), exchangeId.createId(i));
+            Assert.assertEquals(String.format("ex-%010d", i + 1), exchangeId.createId(i + 1));
+        }
     }
 
 }