You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by ve...@apache.org on 2012/12/20 16:40:36 UTC
svn commit: r1424536 - in
/webservices/commons/trunk/modules/axiom/modules/axiom-api/src:
main/java/org/apache/axiom/util/UIDGenerator.java
main/java/org/apache/axiom/util/UUIDCache.java
test/java/org/apache/axiom/util/UIDGeneratorTest.java
Author: veithen
Date: Thu Dec 20 15:40:36 2012
New Revision: 1424536
URL: http://svn.apache.org/viewvc?rev=1424536&view=rev
Log:
Improved the performance of the UIDGenerator#generateURNString() method.
Added:
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UUIDCache.java (with props)
Modified:
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UIDGenerator.java
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/UIDGeneratorTest.java
Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UIDGenerator.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UIDGenerator.java?rev=1424536&r1=1424535&r2=1424536&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UIDGenerator.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UIDGenerator.java Thu Dec 20 15:40:36 2012
@@ -21,6 +21,7 @@ package org.apache.axiom.util;
import java.net.URI;
import java.net.URISyntaxException;
+import java.security.SecureRandom;
import java.util.Random;
import java.util.UUID;
@@ -28,7 +29,8 @@ import java.util.UUID;
* Contains utility methods to generate unique IDs of various kinds.
* <p>
* Depending on the requested type of ID, this class will either use
- * {@link UUID#randomUUID()} or its own unique ID generator. This implementation
+ * {@link UUID#randomUUID()} (or an equivalent algorithm)
+ * or its own unique ID generator. This implementation
* generates unique IDs based on the assumption that the following triplet is
* unique:
* <ol>
@@ -67,11 +69,25 @@ public final class UIDGenerator {
private static final long threadIdXorOperand;
private static final long seqXorOperand;
+ private static final SecureRandom secureRandom = new SecureRandom();
+
+ /**
+ * Array of 16 caches that contain random bytes fetched from {@link #secureRandom} and that are
+ * used to compute UUIDs. These caches are used to reduce the number of calls to
+ * {@link SecureRandom#nextBytes(byte[])}. The cache used by a given thread is determined by the
+ * thread ID. Multiple caches are used to reduce contention between threads.
+ */
+ private static final UUIDCache[] uuidCaches;
+
static {
Random rand = new Random();
threadIdXorOperand = rand.nextLong();
startTimeXorOperand = rand.nextLong();
seqXorOperand = rand.nextLong();
+ uuidCaches = new UUIDCache[16];
+ for (int i=0; i<16; i++) {
+ uuidCaches[i] = new UUIDCache();
+ }
}
/**
@@ -93,10 +109,14 @@ public final class UIDGenerator {
private static void writeReverseLongHex(long value, StringBuilder buffer) {
for (int i=0; i<16; i++) {
int n = (int)(value >> (4*i)) & 0xF;
- buffer.append((char)(n < 10 ? '0' + n : 'a' + n - 10));
+ writeNibble(n, buffer);
}
}
+ private static void writeNibble(int n, StringBuilder buffer) {
+ buffer.append((char)(n < 10 ? '0' + n : 'a' + n - 10));
+ }
+
/**
* Generate a unique ID as hex value and add it to the given buffer. Note
* that with respect to the triplet, the order of nibbles is reversed, i.e.
@@ -210,7 +230,53 @@ public final class UIDGenerator {
* @return the generated URN
*/
public static String generateURNString() {
- return "urn:uuid:" + UUID.randomUUID();
+ StringBuilder urn = new StringBuilder(45);
+ urn.append("urn:uuid:");
+ UUIDCache cache = uuidCaches[(int)Thread.currentThread().getId() & 0xF];
+ synchronized (cache) {
+ boolean fill;
+ int position = cache.position;
+ byte[] randomBytes = cache.randomBytes;
+ if (randomBytes == null) {
+ cache.randomBytes = randomBytes = new byte[4096];
+ fill = true;
+ } else if (position == 4096) {
+ position = 0;
+ fill = true;
+ } else {
+ fill = false;
+ }
+ if (fill) {
+ secureRandom.nextBytes(cache.randomBytes);
+ }
+ writeHex(randomBytes[position], urn);
+ writeHex(randomBytes[position+1], urn);
+ writeHex(randomBytes[position+2], urn);
+ writeHex(randomBytes[position+3], urn);
+ urn.append('-');
+ writeHex(randomBytes[position+4], urn);
+ writeHex(randomBytes[position+5], urn);
+ urn.append('-');
+ writeHex((byte)(randomBytes[position+6] & 0x0F | 0x40), urn);
+ writeHex(randomBytes[position+7], urn);
+ urn.append('-');
+ writeHex((byte)(randomBytes[position+8] & 0x3F | 0x80), urn);
+ writeHex(randomBytes[position+9], urn);
+ urn.append('-');
+ writeHex(randomBytes[position+10], urn);
+ writeHex(randomBytes[position+11], urn);
+ writeHex(randomBytes[position+12], urn);
+ writeHex(randomBytes[position+13], urn);
+ writeHex(randomBytes[position+14], urn);
+ writeHex(randomBytes[position+15], urn);
+ cache.position = position+16;
+ }
+ return urn.toString();
+ }
+
+ private static void writeHex(byte b, StringBuilder buffer) {
+ writeNibble(b >> 4 & 0xF, buffer);
+ writeNibble(b & 0xF, buffer);
}
/**
Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UUIDCache.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UUIDCache.java?rev=1424536&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UUIDCache.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UUIDCache.java Thu Dec 20 15:40:36 2012
@@ -0,0 +1,24 @@
+/*
+ * 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.axiom.util;
+
+final class UUIDCache {
+ int position;
+ byte[] randomBytes;
+}
Propchange: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UUIDCache.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/UIDGeneratorTest.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/UIDGeneratorTest.java?rev=1424536&r1=1424535&r2=1424536&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/UIDGeneratorTest.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/UIDGeneratorTest.java Thu Dec 20 15:40:36 2012
@@ -22,6 +22,7 @@ package org.apache.axiom.util;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
+import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
@@ -45,7 +46,7 @@ public class UIDGeneratorTest extends Te
assertTrue(UIDGenerator.generateMimeBoundary().length() <= 70);
}
- public void testThreadSafety() {
+ public void testGenerateUIDThreadSafety() {
final Set generatedIds = Collections.synchronizedSet(new HashSet());
final AtomicInteger errorCount = new AtomicInteger(0);
Thread[] threads = new Thread[100];
@@ -74,4 +75,40 @@ public class UIDGeneratorTest extends Te
assertEquals(0, errorCount.get());
}
+
+ public void testGenerateURNString() {
+ Thread[] threads = new Thread[100];
+ final String[][] urns = new String[threads.length][1000];
+ for (int i = 0; i < threads.length; i++) {
+ final String[] threadURNs = urns[i];
+ threads[i] = new Thread(new Runnable() {
+ public void run() {
+ for (int i=0; i<threadURNs.length; i++) {
+ threadURNs[i] = UIDGenerator.generateURNString();
+ }
+ }
+ });
+ threads[i].start();
+ }
+
+ for (int i = 0; i < threads.length; i++) {
+ try {
+ threads[i].join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ Set set = new HashSet();
+ for (int i = 0; i < threads.length; i++) {
+ for (int j = 0; j < urns[i].length; j++) {
+ String urn = urns[i][j];
+ assertTrue(urn.startsWith("urn:uuid:"));
+ assertTrue(set.add(urn));
+ UUID uuid = UUID.fromString(urn.substring(9));
+ assertEquals(4, uuid.version());
+ assertEquals(2, uuid.variant());
+ }
+ }
+ }
}