From f8b1b9c387358b22aa6c8de48004a7ff8a4731f2 Mon Sep 17 00:00:00 2001
From: Ivan Sopov <sopov.ivan@gmail.com>
Date: Fri, 23 Mar 2018 22:16:23 +0300
Subject: [PATCH] [core] replace custom ThreadLocalRandom with standard one
 (#1110)

---
 .../src/main/java/com/yahoo/ycsb/BasicDB.java |  3 +-
 core/src/main/java/com/yahoo/ycsb/Client.java |  3 +-
 .../java/com/yahoo/ycsb/GoodBadUglyDB.java    |  3 +-
 .../com/yahoo/ycsb/RandomByteIterator.java    |  4 +-
 core/src/main/java/com/yahoo/ycsb/Utils.java  | 16 +------
 .../ycsb/generator/DiscreteGenerator.java     |  5 +-
 .../ycsb/generator/ExponentialGenerator.java  |  4 +-
 .../ycsb/generator/HistogramGenerator.java    |  5 +-
 .../generator/HotspotIntegerGenerator.java    |  9 ++--
 .../ycsb/generator/UniformLongGenerator.java  |  4 +-
 .../ycsb/generator/ZipfianGenerator.java      |  4 +-
 .../ycsb/workloads/TimeSeriesWorkload.java    | 48 +++++++++----------
 12 files changed, 49 insertions(+), 59 deletions(-)

diff --git a/core/src/main/java/com/yahoo/ycsb/BasicDB.java b/core/src/main/java/com/yahoo/ycsb/BasicDB.java
index 15d11010..3972da69 100644
--- a/core/src/main/java/com/yahoo/ycsb/BasicDB.java
+++ b/core/src/main/java/com/yahoo/ycsb/BasicDB.java
@@ -20,6 +20,7 @@ package com.yahoo.ycsb;
 import java.util.*;
 import java.util.Map.Entry;
 import java.util.Map;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.LockSupport;
 
@@ -60,7 +61,7 @@ public class BasicDB extends DB {
     if (todelay > 0) {
       long delayNs;
       if (randomizedelay) {
-        delayNs = TimeUnit.MILLISECONDS.toNanos(Utils.random().nextInt(todelay));
+        delayNs = TimeUnit.MILLISECONDS.toNanos(ThreadLocalRandom.current().nextInt(todelay));
         if (delayNs == 0) {
           return;
         }
diff --git a/core/src/main/java/com/yahoo/ycsb/Client.java b/core/src/main/java/com/yahoo/ycsb/Client.java
index 1e31c112..e8b70600 100644
--- a/core/src/main/java/com/yahoo/ycsb/Client.java
+++ b/core/src/main/java/com/yahoo/ycsb/Client.java
@@ -33,6 +33,7 @@ import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.Map.Entry;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.LockSupport;
 
@@ -442,7 +443,7 @@ class ClientThread implements Runnable {
     // GH issue 4 - throws exception if _target>1 because random.nextInt argument must be >0
     // and the sleep() doesn't make sense for granularities < 1 ms anyway
     if ((targetOpsPerMs > 0) && (targetOpsPerMs <= 1.0)) {
-      long randomMinorDelay = Utils.random().nextInt((int) targetOpsTickNs);
+      long randomMinorDelay = ThreadLocalRandom.current().nextInt((int) targetOpsTickNs);
       sleepUntil(System.nanoTime() + randomMinorDelay);
     }
     try {
diff --git a/core/src/main/java/com/yahoo/ycsb/GoodBadUglyDB.java b/core/src/main/java/com/yahoo/ycsb/GoodBadUglyDB.java
index 1cbf3a5d..384e1387 100644
--- a/core/src/main/java/com/yahoo/ycsb/GoodBadUglyDB.java
+++ b/core/src/main/java/com/yahoo/ycsb/GoodBadUglyDB.java
@@ -22,6 +22,7 @@ import java.util.Map;
 import java.util.Random;
 import java.util.Set;
 import java.util.Vector;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.LockSupport;
 import java.util.concurrent.locks.ReadWriteLock;
@@ -43,7 +44,7 @@ public class GoodBadUglyDB extends DB {
   }
 
   private void delay() {
-    final Random random = Utils.random();
+    final Random random = ThreadLocalRandom.current();
     double p = random.nextDouble();
     int mod;
     if (p < 0.9) {
diff --git a/core/src/main/java/com/yahoo/ycsb/RandomByteIterator.java b/core/src/main/java/com/yahoo/ycsb/RandomByteIterator.java
index 681224e8..e21689cc 100644
--- a/core/src/main/java/com/yahoo/ycsb/RandomByteIterator.java
+++ b/core/src/main/java/com/yahoo/ycsb/RandomByteIterator.java
@@ -16,6 +16,8 @@
  */
 package com.yahoo.ycsb;
 
+import java.util.concurrent.ThreadLocalRandom;
+
 /**
  *  A ByteIterator that generates a random sequence of bytes.
  */
@@ -31,7 +33,7 @@ public class RandomByteIterator extends ByteIterator {
   }
 
   private void fillBytesImpl(byte[] buffer, int base) {
-    int bytes = Utils.random().nextInt();
+    int bytes = ThreadLocalRandom.current().nextInt();
 
     switch (buffer.length - base) {
     default:
diff --git a/core/src/main/java/com/yahoo/ycsb/Utils.java b/core/src/main/java/com/yahoo/ycsb/Utils.java
index ade6a1ce..9fdf079e 100644
--- a/core/src/main/java/com/yahoo/ycsb/Utils.java
+++ b/core/src/main/java/com/yahoo/ycsb/Utils.java
@@ -23,7 +23,7 @@ import java.lang.management.OperatingSystemMXBean;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
 
 /**
  * Utility functions.
@@ -33,18 +33,6 @@ public final class Utils {
     // not used
   }
 
-  private static final Random RAND = new Random();
-  private static final ThreadLocal<Random> RNG = new ThreadLocal<Random>();
-
-  public static Random random() {
-    Random ret = RNG.get();
-    if (ret == null) {
-      ret = new Random(RAND.nextLong());
-      RNG.set(ret);
-    }
-    return ret;
-  }
-
   /**
    * Hash an integer value.
    */
@@ -234,7 +222,7 @@ public final class Utils {
    */
   public static <T> T [] shuffleArray(final T[] array) {
     for (int i = array.length -1; i > 0; i--) {
-      final int idx = RAND.nextInt(i + 1);
+      final int idx = ThreadLocalRandom.current().nextInt(i + 1);
       final T temp = array[idx];
       array[idx] = array[i];
       array[i] = temp;
diff --git a/core/src/main/java/com/yahoo/ycsb/generator/DiscreteGenerator.java b/core/src/main/java/com/yahoo/ycsb/generator/DiscreteGenerator.java
index fa7caf4b..c445f055 100644
--- a/core/src/main/java/com/yahoo/ycsb/generator/DiscreteGenerator.java
+++ b/core/src/main/java/com/yahoo/ycsb/generator/DiscreteGenerator.java
@@ -17,10 +17,9 @@
 
 package com.yahoo.ycsb.generator;
 
-import com.yahoo.ycsb.Utils;
-
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.concurrent.ThreadLocalRandom;
 
 import static java.util.Objects.requireNonNull;
 
@@ -56,7 +55,7 @@ public class DiscreteGenerator extends Generator<String> {
       sum += p.weight;
     }
 
-    double val = Utils.random().nextDouble();
+    double val = ThreadLocalRandom.current().nextDouble();
 
     for (Pair p : values) {
       double pw = p.weight / sum;
diff --git a/core/src/main/java/com/yahoo/ycsb/generator/ExponentialGenerator.java b/core/src/main/java/com/yahoo/ycsb/generator/ExponentialGenerator.java
index 4ff7296a..cb3247c7 100644
--- a/core/src/main/java/com/yahoo/ycsb/generator/ExponentialGenerator.java
+++ b/core/src/main/java/com/yahoo/ycsb/generator/ExponentialGenerator.java
@@ -17,7 +17,7 @@
 
 package com.yahoo.ycsb.generator;
 
-import com.yahoo.ycsb.Utils;
+import java.util.concurrent.ThreadLocalRandom;
 
 /**
  * A generator of an exponential distribution. It produces a sequence
@@ -66,7 +66,7 @@ public class ExponentialGenerator extends NumberGenerator {
    */
   @Override
   public Double nextValue() {
-    return -Math.log(Utils.random().nextDouble()) / gamma;
+    return -Math.log(ThreadLocalRandom.current().nextDouble()) / gamma;
   }
 
   @Override
diff --git a/core/src/main/java/com/yahoo/ycsb/generator/HistogramGenerator.java b/core/src/main/java/com/yahoo/ycsb/generator/HistogramGenerator.java
index 766de44c..f5dc0b33 100644
--- a/core/src/main/java/com/yahoo/ycsb/generator/HistogramGenerator.java
+++ b/core/src/main/java/com/yahoo/ycsb/generator/HistogramGenerator.java
@@ -16,12 +16,11 @@
  */
 package com.yahoo.ycsb.generator;
 
-import com.yahoo.ycsb.Utils;
-
 import java.io.BufferedReader;
 import java.io.FileReader;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.concurrent.ThreadLocalRandom;
 
 /**
  * Generate integers according to a histogram distribution.  The histogram
@@ -89,7 +88,7 @@ public class HistogramGenerator extends NumberGenerator {
 
   @Override
   public Long nextValue() {
-    int number = Utils.random().nextInt((int) area);
+    int number = ThreadLocalRandom.current().nextInt((int) area);
     int i;
 
     for (i = 0; i < (buckets.length - 1); i++) {
diff --git a/core/src/main/java/com/yahoo/ycsb/generator/HotspotIntegerGenerator.java b/core/src/main/java/com/yahoo/ycsb/generator/HotspotIntegerGenerator.java
index 677ebd2f..73a9882d 100644
--- a/core/src/main/java/com/yahoo/ycsb/generator/HotspotIntegerGenerator.java
+++ b/core/src/main/java/com/yahoo/ycsb/generator/HotspotIntegerGenerator.java
@@ -16,9 +16,8 @@
  */
 package com.yahoo.ycsb.generator;
 
-import com.yahoo.ycsb.Utils;
-
 import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
 
 /**
  * Generate integers resembling a hotspot distribution where x% of operations
@@ -75,13 +74,13 @@ public class HotspotIntegerGenerator extends NumberGenerator {
   @Override
   public Long nextValue() {
     long value = 0;
-    Random random = Utils.random();
+    Random random = ThreadLocalRandom.current();
     if (random.nextDouble() < hotOpnFraction) {
       // Choose a value from the hot set.
-      value = lowerBound + Math.abs(Utils.random().nextLong()) % hotInterval;
+      value = lowerBound + Math.abs(random.nextLong()) % hotInterval;
     } else {
       // Choose a value from the cold set.
-      value = lowerBound + hotInterval + Math.abs(Utils.random().nextLong()) % coldInterval;
+      value = lowerBound + hotInterval + Math.abs(random.nextLong()) % coldInterval;
     }
     setLastValue(value);
     return value;
diff --git a/core/src/main/java/com/yahoo/ycsb/generator/UniformLongGenerator.java b/core/src/main/java/com/yahoo/ycsb/generator/UniformLongGenerator.java
index 2d1994f9..f042284d 100644
--- a/core/src/main/java/com/yahoo/ycsb/generator/UniformLongGenerator.java
+++ b/core/src/main/java/com/yahoo/ycsb/generator/UniformLongGenerator.java
@@ -17,7 +17,7 @@
 
 package com.yahoo.ycsb.generator;
 
-import com.yahoo.ycsb.Utils;
+import java.util.concurrent.ThreadLocalRandom;
 
 /**
  * Generates longs randomly uniform from an interval.
@@ -41,7 +41,7 @@ public class UniformLongGenerator extends NumberGenerator {
 
   @Override
   public Long nextValue() {
-    long ret = Math.abs(Utils.random().nextLong()) % interval  + lb;
+    long ret = Math.abs(ThreadLocalRandom.current().nextLong()) % interval  + lb;
     setLastValue(ret);
 
     return ret;
diff --git a/core/src/main/java/com/yahoo/ycsb/generator/ZipfianGenerator.java b/core/src/main/java/com/yahoo/ycsb/generator/ZipfianGenerator.java
index a6514eda..bf13e870 100644
--- a/core/src/main/java/com/yahoo/ycsb/generator/ZipfianGenerator.java
+++ b/core/src/main/java/com/yahoo/ycsb/generator/ZipfianGenerator.java
@@ -17,7 +17,7 @@
 
 package com.yahoo.ycsb.generator;
 
-import com.yahoo.ycsb.Utils;
+import java.util.concurrent.ThreadLocalRandom;
 
 /**
  * A generator of a zipfian distribution. It produces a sequence of items, such that some items are more popular than
@@ -247,7 +247,7 @@ public class ZipfianGenerator extends NumberGenerator {
       }
     }
 
-    double u = Utils.random().nextDouble();
+    double u = ThreadLocalRandom.current().nextDouble();
     double uz = u * zetan;
 
     if (uz < 1.0) {
diff --git a/core/src/main/java/com/yahoo/ycsb/workloads/TimeSeriesWorkload.java b/core/src/main/java/com/yahoo/ycsb/workloads/TimeSeriesWorkload.java
index 5d0eabd0..be97b206 100644
--- a/core/src/main/java/com/yahoo/ycsb/workloads/TimeSeriesWorkload.java
+++ b/core/src/main/java/com/yahoo/ycsb/workloads/TimeSeriesWorkload.java
@@ -21,9 +21,11 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
+import java.util.Random;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.Vector;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
 
 import com.yahoo.ycsb.ByteIterator;
@@ -731,9 +733,9 @@ public class TimeSeriesWorkload extends Workload {
   protected void doTransactionRead(final DB db, Object threadstate) {
     final ThreadState state = (ThreadState) threadstate;
     final String keyname = keys[keychooser.nextValue().intValue()];
-    
+    final Random random = ThreadLocalRandom.current();
     int offsets = state.queryOffsetGenerator.nextValue().intValue();
-    //int offsets = Utils.random().nextInt(maxOffsets - 1);
+    //int offsets = random.nextInt(maxOffsets - 1);
     final long startTimestamp;
     if (offsets > 0) {
       startTimestamp = state.startTimestamp + state.timestampGenerator.getOffset(offsets);
@@ -748,14 +750,14 @@ public class TimeSeriesWorkload extends Workload {
         fields.add(tagKeys[i]);
       } else {
         fields.add(tagKeys[i] + tagPairDelimiter + 
-            tagValues[Utils.random().nextInt(tagCardinality[i])]);
+            tagValues[random.nextInt(tagCardinality[i])]);
       }
     }
     
     if (queryTimeSpan > 0) {
       final long endTimestamp;
       if (queryRandomTimeSpan) {
-        endTimestamp = startTimestamp + (timestampInterval * Utils.random().nextInt(queryTimeSpan / timestampInterval));
+        endTimestamp = startTimestamp + (timestampInterval * random.nextInt(queryTimeSpan / timestampInterval));
       } else {
         endTimestamp = startTimestamp + queryTimeSpan;
       }
@@ -793,13 +795,13 @@ public class TimeSeriesWorkload extends Workload {
   
   protected void doTransactionScan(final DB db, Object threadstate) {
     final ThreadState state = (ThreadState) threadstate;
-    
-    final String keyname = keys[Utils.random().nextInt(keys.length)];
+    final Random random = ThreadLocalRandom.current();
+    final String keyname = keys[random.nextInt(keys.length)];
     
     // choose a random scan length
     int len = scanlength.nextValue().intValue();
     
-    int offsets = Utils.random().nextInt(maxOffsets - 1);
+    int offsets = random.nextInt(maxOffsets - 1);
     final long startTimestamp;
     if (offsets > 0) {
       startTimestamp = state.startTimestamp + state.timestampGenerator.getOffset(offsets);
@@ -814,14 +816,14 @@ public class TimeSeriesWorkload extends Workload {
         fields.add(tagKeys[i]);
       } else {
         fields.add(tagKeys[i] + tagPairDelimiter + 
-            tagValues[Utils.random().nextInt(tagCardinality[i])]);
+            tagValues[random.nextInt(tagCardinality[i])]);
       }
     }
     
     if (queryTimeSpan > 0) {
       final long endTimestamp;
       if (queryRandomTimeSpan) {
-        endTimestamp = startTimestamp + (timestampInterval * Utils.random().nextInt(queryTimeSpan / timestampInterval));
+        endTimestamp = startTimestamp + (timestampInterval * random.nextInt(queryTimeSpan / timestampInterval));
       } else {
         endTimestamp = startTimestamp + queryTimeSpan;
       }
@@ -842,10 +844,10 @@ public class TimeSeriesWorkload extends Workload {
   
   protected void doTransactionDelete(final DB db, Object threadstate) {
     final ThreadState state = (ThreadState) threadstate;
+    final Random random = ThreadLocalRandom.current();
+    final StringBuilder buf = new StringBuilder().append(keys[random.nextInt(keys.length)]);
     
-    final StringBuilder buf = new StringBuilder().append(keys[Utils.random().nextInt(keys.length)]);
-    
-    int offsets = Utils.random().nextInt(maxOffsets - 1);
+    int offsets = random.nextInt(maxOffsets - 1);
     final long startTimestamp;
     if (offsets > 0) {
       startTimestamp = state.startTimestamp + state.timestampGenerator.getOffset(offsets);
@@ -860,14 +862,14 @@ public class TimeSeriesWorkload extends Workload {
            .append(tagKeys[i]);
       } else {
         buf.append(deleteDelimiter).append(tagKeys[i] + tagPairDelimiter + 
-            tagValues[Utils.random().nextInt(tagCardinality[i])]);
+            tagValues[random.nextInt(tagCardinality[i])]);
       }
     }
     
     if (queryTimeSpan > 0) {
       final long endTimestamp;
       if (queryRandomTimeSpan) {
-        endTimestamp = startTimestamp + (timestampInterval * Utils.random().nextInt(queryTimeSpan / timestampInterval));
+        endTimestamp = startTimestamp + (timestampInterval * random.nextInt(queryTimeSpan / timestampInterval));
       } else {
         endTimestamp = startTimestamp + queryTimeSpan;
       }
@@ -1168,8 +1170,8 @@ public class TimeSeriesWorkload extends Workload {
      * @return The next key to write.
      */
     protected String nextDataPoint(final Map<String, ByteIterator> map, final boolean isInsert) {
-      int iterations = sparsity <= 0 ? 1 : 
-          Utils.random().nextInt((int) ((double) perKeyCardinality * sparsity));
+      final Random random = ThreadLocalRandom.current();
+      int iterations = sparsity <= 0 ? 1 : random.nextInt((int) ((double) perKeyCardinality * sparsity));
       if (iterations < 1) {
         iterations = 1;
       }
@@ -1202,7 +1204,7 @@ public class TimeSeriesWorkload extends Workload {
           
           if (!isInsert) {
             final long delta = (timestampGenerator.currentValue() - startTimestamp) / timestampInterval;
-            final int intervals = Utils.random().nextInt((int) delta);
+            final int intervals = random.nextInt((int) delta);
             map.put(timestampKey, new NumericByteIterator(startTimestamp + (intervals * timestampInterval)));
           } else if (delayedSeries > 0) {
             // See if the series falls in a delay bucket and calculate an offset earlier
@@ -1228,18 +1230,16 @@ public class TimeSeriesWorkload extends Workload {
           } else {
             switch (valueType) {
             case INTEGERS:
-              map.put(valueKey, new NumericByteIterator(Utils.random().nextInt()));
+              map.put(valueKey, new NumericByteIterator(random.nextInt()));
               break;
             case FLOATS:
-              map.put(valueKey, new NumericByteIterator(
-                  Utils.random().nextDouble() * (double) 100000));
+              map.put(valueKey, new NumericByteIterator(random.nextDouble() * (double) 100000));
               break;
             case MIXED:
-              if (Utils.random().nextBoolean()) {
-                map.put(valueKey, new NumericByteIterator(Utils.random().nextInt()));
+              if (random.nextBoolean()) {
+                map.put(valueKey, new NumericByteIterator(random.nextInt()));
               } else {
-                map.put(valueKey, new NumericByteIterator(
-                    Utils.random().nextDouble() * (double) 100000));
+                map.put(valueKey, new NumericByteIterator(random.nextDouble() * (double) 100000));
               }
               break;
             default:
-- 
GitLab