// Copyright 2017 JanusGraph Authors // // Licensed 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.janusgraph.graphdb.idmanagement; import com.google.common.base.Preconditions; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.janusgraph.diskstorage.StaticBuffer; import org.janusgraph.diskstorage.keycolumnvalue.KeyRange; import org.janusgraph.diskstorage.util.BufferUtil; import org.janusgraph.graphdb.database.idassigner.placement.PartitionIDRange; import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; import java.util.Arrays; import java.util.List; import java.util.Set; import static org.junit.Assert.*; /** * @author Matthias Broecheler (me@matthiasb.com) */ public class PartitionIDRangeTest { @Test public void basicIDRangeTest() { PartitionIDRange pr; for (int[] bounds : new int[][]{{0,16},{5,5},{9,9},{0,0}}) { pr = new PartitionIDRange(bounds[0], bounds[1], 16); Set<Integer> allIds = Sets.newHashSet(Arrays.asList(ArrayUtils.toObject(pr.getAllContainedIDs()))); assertEquals(16, allIds.size()); for (int i = 0; i < 16; i++) { assertTrue(allIds.contains(i)); assertTrue(pr.contains(i)); } assertFalse(pr.contains(16)); verifyRandomSampling(pr); } pr = new PartitionIDRange(13,2,16); assertTrue(pr.contains(15)); assertTrue(pr.contains(1)); assertEquals(5,pr.getAllContainedIDs().length); verifyRandomSampling(pr); pr = new PartitionIDRange(512,2,2048); assertEquals(2048-512+2,pr.getAllContainedIDs().length); verifyRandomSampling(pr); pr = new PartitionIDRange(512,1055,2048); assertEquals(1055-512,pr.getAllContainedIDs().length); verifyRandomSampling(pr); try { pr = new PartitionIDRange(0,5,4); fail(); } catch (IllegalArgumentException e) {} try { pr = new PartitionIDRange(5,3,4); fail(); } catch (IllegalArgumentException e) {} try { pr = new PartitionIDRange(-1,3,4); fail(); } catch (IllegalArgumentException e) {} } private void verifyRandomSampling(PartitionIDRange pr) { Set<Integer> allIds = Sets.newHashSet(Arrays.asList(ArrayUtils.toObject(pr.getAllContainedIDs()))); /* Verify that the probability of NOT sampling the whole space is exceedingly small The probability of NOT sampling (with replacement) a single element from a set of x elements in T trials is: ((x-1)/x)^T Hence, an upper bound for not sampling any of the elements (assuming independence turning OR into +) is: x * ((x-1)/x)^T */ double x = allIds.size(); final int T = 300000; double failureSampleProb = x * Math.pow((x-1)/x,T); assertTrue(failureSampleProb<1e-12); //Make sure the failure prob is infinitisimally small Set<Integer> randomIds = Sets.newHashSet(); for (int t=0;t<T;t++) { int id = pr.getRandomID(); randomIds.add(id); assertTrue(allIds.contains(id)); } assertEquals(allIds.size(),randomIds.size()); } @Test public void convertIDRangesFromBits() { PartitionIDRange pr; for (int partitionBits : new int[]{0,1,4,16,5,7,2}) { pr = Iterables.getOnlyElement(PartitionIDRange.getGlobalRange(partitionBits)); assertEquals(1<<partitionBits,pr.getUpperID()); assertEquals(1<<partitionBits,pr.getAllContainedIDs().length); if (partitionBits<=10) verifyRandomSampling(pr); } try { PartitionIDRange.getGlobalRange(-1); fail(); } catch (IllegalArgumentException e) {} } @Test public void convertIDRangesFromBuffers() { PartitionIDRange pr; pr = getPIR(2,2,6,3); assertEquals(2, pr.getAllContainedIDs().length); assertTrue(pr.contains(1)); assertTrue(pr.contains(2)); assertFalse(pr.contains(3)); pr = getPIR(2,3,6,3); assertEquals(1, pr.getAllContainedIDs().length); assertFalse(pr.contains(1)); assertTrue(pr.contains(2)); assertFalse(pr.contains(3)); pr = getPIR(4,2,6,3); assertEquals(8, pr.getAllContainedIDs().length); pr = getPIR(2,6,6,3); assertEquals(4,pr.getAllContainedIDs().length); pr = getPIR(2,7,7,3); assertEquals(4,pr.getAllContainedIDs().length); pr = getPIR(2,10,9,4); assertEquals(3,pr.getAllContainedIDs().length); pr = getPIR(2,5,15,4); assertEquals(1, pr.getAllContainedIDs().length); pr = getPIR(2,9,16,4); assertEquals(1, pr.getAllContainedIDs().length); assertTrue(pr.contains(3)); assertNull(getPIR(2, 11, 12, 4)); assertNull(getPIR(2, 5, 11, 4)); assertNull(getPIR(2, 9, 12, 4)); assertNull(getPIR(2, 9, 11, 4)); assertNull(getPIR(2, 13, 15, 4)); assertNull(getPIR(2, 13, 3, 4)); pr = getPIR(2,15,14,4); assertEquals(3,pr.getAllContainedIDs().length); pr = getPIR(1,7,6,3); assertEquals(1, pr.getAllContainedIDs().length); assertTrue(pr.contains(0)); } public static PartitionIDRange getPIR(int partitionBits, long lower, long upper, int bitwidth) { return Iterables.getOnlyElement(PartitionIDRange.getIDRanges(partitionBits, convert(lower, upper, bitwidth)), null); } public static List<KeyRange> convert(long lower, long upper, int bitwidth) { StaticBuffer lowerBuffer = BufferUtil.getLongBuffer(convert(lower, bitwidth)); StaticBuffer upperBuffer = BufferUtil.getLongBuffer(convert(upper, bitwidth)); // Preconditions.checkArgument(lowerBuffer.compareTo(upperBuffer) < 0, "%s vs %s",lowerBuffer,upperBuffer); return Lists.newArrayList(new KeyRange(lowerBuffer, upperBuffer)); } public static long convert(long id, int bitwidth) { Preconditions.checkArgument(id>=0 && id<=(1<<bitwidth)); return id<<(64-bitwidth); } }