public static void main(String[] args) throws ExecutionException, InterruptedException, InvocationTargetException, IllegalAccessException { for (String arg : args) { if (arg.startsWith("fan=")) System.setProperty("cassandra.btree.fanfactor", arg.substring(4)); else if (arg.startsWith("min=")) minTreeSize = Integer.parseInt(arg.substring(4)); else if (arg.startsWith("max=")) maxTreeSize = Integer.parseInt(arg.substring(4)); else if (arg.startsWith("count=")) perThreadTrees = Integer.parseInt(arg.substring(6)); else exit(); } List<Method> methods = new ArrayList<>(); for (Method m : LongBTreeTest.class.getDeclaredMethods()) { if (m.getParameters().length > 0) continue; for (Annotation annotation : m.getAnnotations()) if (annotation.annotationType() == Test.class) methods.add(m); } LongBTreeTest test = new LongBTreeTest(); Collections.sort(methods, (a, b) -> a.getName().compareTo(b.getName())); log(Lists.transform(methods, (m) -> m.getName()).toString()); for (Method m : methods) { log(m.getName()); m.invoke(test); } log("success"); }
// select a random subset of the keys, with an optional random population of keys inbetween those // that are present // return a value with the search position private static List<Integer> randomKeys( Iterable<Integer> canonical, boolean mixInNotPresentItems) { ThreadLocalRandom rnd = ThreadLocalRandom.current(); boolean useFake = mixInNotPresentItems && rnd.nextBoolean(); final float fakeRatio = rnd.nextFloat(); List<Integer> results = new ArrayList<>(); Long fakeLb = null, fakeUb = null; for (Integer v : canonical) { if (!useFake || fakeLb == null || (fakeUb == null ? v - 1 : fakeUb) <= fakeLb + 1 || rnd.nextFloat() < fakeRatio) { // if we cannot safely construct a fake value, or our randomizer says not to, we emit the // next real value results.add(v); fakeLb = v.longValue(); fakeUb = null; } else { // otherwise we emit a fake value in the range immediately proceeding the last real value, // and not // exceeding the real value that would have proceeded (ignoring any other suppressed real // values since) if (fakeUb == null) fakeUb = v.longValue() - 1; long mid = (fakeLb + fakeUb) / 2; assert mid < fakeUb; results.add((int) mid); fakeLb = mid; } } final float useChance = rnd.nextFloat(); return Lists.newArrayList(filter(results, (x) -> rnd.nextFloat() < useChance)); }
private static RandomTree randomTreeByBuilder(int minSize, int maxSize) { assert minSize > 3; ThreadLocalRandom random = ThreadLocalRandom.current(); BTree.Builder<Integer> builder = BTree.builder(naturalOrder()); int targetSize = random.nextInt(minSize, maxSize); int maxModificationSize = (int) Math.sqrt(targetSize); TreeSet<Integer> canonical = new TreeSet<>(); int curSize = 0; TreeSet<Integer> ordered = new TreeSet<>(); List<Integer> shuffled = new ArrayList<>(); while (curSize < targetSize) { int nextSize = maxModificationSize <= 1 ? 1 : random.nextInt(1, maxModificationSize); // leave a random selection of previous values (random.nextBoolean() ? ordered.headSet(random.nextInt()) : ordered.tailSet(random.nextInt())) .clear(); shuffled = new ArrayList<>( shuffled.subList(0, shuffled.size() < 2 ? 0 : random.nextInt(shuffled.size() / 2))); for (int i = 0; i < nextSize; i++) { Integer next = random.nextInt(); ordered.add(next); shuffled.add(next); canonical.add(next); } switch (random.nextInt(5)) { case 0: builder.addAll(ordered); break; case 1: builder.addAll(BTreeSet.of(ordered)); break; case 2: for (Integer i : ordered) builder.add(i); case 3: builder.addAll(shuffled); break; case 4: for (Integer i : shuffled) builder.add(i); } curSize += nextSize; maxModificationSize = Math.min(maxModificationSize, targetSize - curSize); } BTreeSet<Integer> btree = BTreeSet.<Integer>wrap(builder.build(), naturalOrder()); Assert.assertEquals(canonical.size(), btree.size()); return new RandomTree(canonical, btree); }
RandomSelection select(boolean narrow, boolean mixInNotPresentItems, boolean permitReversal) { ThreadLocalRandom random = ThreadLocalRandom.current(); NavigableSet<Integer> canonicalSet = this.canonical; BTreeSet<Integer> testAsSet = this.test; List<Integer> canonicalList = new ArrayList<>(canonicalSet); BTreeSet<Integer> testAsList = this.test; Assert.assertEquals(canonicalSet.size(), testAsSet.size()); Assert.assertEquals(canonicalList.size(), testAsList.size()); // sometimes select keys first, so we cover full range List<Integer> allKeys = randomKeys(canonical, mixInNotPresentItems); List<Integer> keys = allKeys; int narrowCount = random.nextInt(3); while (narrow && canonicalList.size() > 10 && keys.size() > 10 && narrowCount-- > 0) { boolean useLb = random.nextBoolean(); boolean useUb = random.nextBoolean(); if (!(useLb | useUb)) continue; // select a range smaller than the total span when we have more narrowing iterations left int indexRange = keys.size() / (narrowCount + 1); boolean lbInclusive = true; Integer lbKey = canonicalList.get(0); int lbKeyIndex = 0, lbIndex = 0; boolean ubInclusive = true; Integer ubKey = canonicalList.get(canonicalList.size() - 1); int ubKeyIndex = keys.size(), ubIndex = canonicalList.size(); if (useLb) { lbKeyIndex = random.nextInt(0, indexRange - 1); Integer candidate = keys.get(lbKeyIndex); if (useLb = (candidate > lbKey && candidate <= ubKey)) { lbInclusive = random.nextBoolean(); lbKey = keys.get(lbKeyIndex); lbIndex = Collections.binarySearch(canonicalList, lbKey); if (lbIndex >= 0 && !lbInclusive) lbIndex++; else if (lbIndex < 0) lbIndex = -1 - lbIndex; } } if (useUb) { ubKeyIndex = random.nextInt(Math.max(lbKeyIndex, keys.size() - indexRange), keys.size() - 1); Integer candidate = keys.get(ubKeyIndex); if (useUb = (candidate < ubKey && candidate >= lbKey)) { ubInclusive = random.nextBoolean(); ubKey = keys.get(ubKeyIndex); ubIndex = Collections.binarySearch(canonicalList, ubKey); if (ubIndex >= 0 && ubInclusive) { ubIndex++; } else if (ubIndex < 0) ubIndex = -1 - ubIndex; } } if (ubIndex < lbIndex) { ubIndex = lbIndex; ubKey = lbKey; ubInclusive = false; } canonicalSet = !useLb ? canonicalSet.headSet(ubKey, ubInclusive) : !useUb ? canonicalSet.tailSet(lbKey, lbInclusive) : canonicalSet.subSet(lbKey, lbInclusive, ubKey, ubInclusive); testAsSet = !useLb ? testAsSet.headSet(ubKey, ubInclusive) : !useUb ? testAsSet.tailSet(lbKey, lbInclusive) : testAsSet.subSet(lbKey, lbInclusive, ubKey, ubInclusive); keys = keys.subList(lbKeyIndex, ubKeyIndex); canonicalList = canonicalList.subList(lbIndex, ubIndex); testAsList = testAsList.subList(lbIndex, ubIndex); Assert.assertEquals(canonicalSet.size(), testAsSet.size()); Assert.assertEquals(canonicalList.size(), testAsList.size()); } // possibly restore full set of keys, to test case where we are provided existing keys that // are out of bounds if (keys != allKeys && random.nextBoolean()) keys = allKeys; Comparator<Integer> comparator = naturalOrder(); if (permitReversal && random.nextBoolean()) { if (allKeys != keys) keys = new ArrayList<>(keys); if (canonicalSet != canonical) canonicalList = new ArrayList<>(canonicalList); Collections.reverse(keys); Collections.reverse(canonicalList); testAsList = testAsList.descendingSet(); canonicalSet = canonicalSet.descendingSet(); testAsSet = testAsSet.descendingSet(); comparator = reverseOrder(); } Assert.assertEquals(canonicalSet.size(), testAsSet.size()); Assert.assertEquals(canonicalList.size(), testAsList.size()); if (!canonicalSet.isEmpty()) { Assert.assertEquals(canonicalSet.first(), canonicalList.get(0)); Assert.assertEquals(canonicalSet.last(), canonicalList.get(canonicalList.size() - 1)); Assert.assertEquals(canonicalSet.first(), testAsSet.first()); Assert.assertEquals(canonicalSet.last(), testAsSet.last()); Assert.assertEquals(canonicalSet.first(), testAsList.get(0)); Assert.assertEquals(canonicalSet.last(), testAsList.get(testAsList.size() - 1)); } return new RandomSelection( keys, canonicalSet, testAsSet, canonicalList, testAsList, comparator); }