HBASE-24163 MOB compactor implementations should use format specifiers when calling...
[hbase.git] / hbase-common / src / main / java / org / apache / hadoop / hbase / util / Random64.java
blobf337b5f745dc2255bc831417cf849cf16868431e
1 /**
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
20 package org.apache.hadoop.hbase.util;
22 import java.util.HashSet;
23 import java.util.Random;
24 import java.util.Set;
25 import java.util.concurrent.atomic.AtomicLong;
26 import org.apache.yetus.audience.InterfaceAudience;
27 import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
29 /**
31 * An instance of this class is used to generate a stream of
32 * pseudorandom numbers. The class uses a 64-bit seed, which is
33 * modified using a linear congruential formula.
35 * see https://en.wikipedia.org/wiki/Linear_congruential_generator
37 @InterfaceAudience.Private
38 public class Random64 {
40 private static final long multiplier = 6364136223846793005L;
41 private static final long addend = 1442695040888963407L;
43 private static final AtomicLong seedUniquifier
44 = new AtomicLong(8682522807148012L);
46 private long seed;
48 /**
49 * Copy from {@link Random#seedUniquifier()}
51 private static long seedUniquifier() {
52 for (; ; ) {
53 long current = seedUniquifier.get();
54 long next = current * 181783497276652981L;
55 if (seedUniquifier.compareAndSet(current, next)) {
56 return next;
61 public Random64() {
62 this(seedUniquifier() ^ System.nanoTime());
65 public Random64(long seed) {
66 this.seed = seed;
69 public long nextLong() {
70 return next64(64);
73 public void nextBytes(byte[] bytes) {
74 for (int i = 0, len = bytes.length; i < len;) {
75 // We regard seed as unsigned long, therefore used '>>>' instead of '>>'.
76 for (long rnd = nextLong(), n = Math.min(len - i, Long.SIZE / Byte.SIZE);
77 n-- > 0; rnd >>>= Byte.SIZE) {
78 bytes[i++] = (byte) rnd;
83 private long next64(int bits) {
84 seed = seed * multiplier + addend;
85 return seed >>> (64 - bits);
89 /**
90 * Random64 is a pseudorandom algorithm(LCG). Therefore, we will get same sequence
91 * if seeds are the same. This main will test how many calls nextLong() it will
92 * get the same seed.
94 * We do not need to save all numbers (that is too large). We could save
95 * once every 100000 calls nextLong(). If it get a same seed, we can
96 * detect this by calling nextLong() 100000 times continuously.
99 public static void main(String[] args) {
100 long defaultTotalTestCnt = 1000000000000L; // 1 trillion
102 if (args.length == 1) {
103 defaultTotalTestCnt = Long.parseLong(args[0]);
106 Preconditions.checkArgument(defaultTotalTestCnt > 0, "totalTestCnt <= 0");
108 final int precision = 100000;
109 final long totalTestCnt = defaultTotalTestCnt + precision;
110 final int reportPeriod = 100 * precision;
111 final long startTime = System.currentTimeMillis();
113 System.out.println("Do collision test, totalTestCnt=" + totalTestCnt);
115 Random64 rand = new Random64();
116 Set<Long> longSet = new HashSet<>();
118 for (long cnt = 1; cnt <= totalTestCnt; cnt++) {
119 final long randLong = rand.nextLong();
121 if (longSet.contains(randLong)) {
122 System.err.println("Conflict! count=" + cnt);
123 System.exit(1);
126 if (cnt % precision == 0) {
127 if (!longSet.add(randLong)) {
128 System.err.println("Conflict! count=" + cnt);
129 System.exit(1);
132 if (cnt % reportPeriod == 0) {
133 long cost = System.currentTimeMillis() - startTime;
134 long remainingMs = (long) (1.0 * (totalTestCnt - cnt) * cost / cnt);
135 System.out.println(
136 String.format(
137 "Progress: %.3f%%, remaining %d minutes",
138 100.0 * cnt / totalTestCnt, remainingMs / 60000
146 System.out.println("No collision!");