| /* |
| * 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.datasketches.theta; |
| |
| import static java.lang.foreign.ValueLayout.JAVA_BYTE; |
| import static org.apache.datasketches.theta.PreambleUtil.FAMILY_BYTE; |
| import static org.apache.datasketches.theta.PreambleUtil.LG_NOM_LONGS_BYTE; |
| import static org.apache.datasketches.theta.PreambleUtil.SER_VER_BYTE; |
| import static org.testng.Assert.assertEquals; |
| import static org.testng.Assert.assertFalse; |
| import static org.testng.Assert.assertTrue; |
| import static org.testng.Assert.fail; |
| |
| import java.lang.foreign.MemorySegment; |
| import java.util.Arrays; |
| |
| import org.apache.datasketches.common.Family; |
| import org.apache.datasketches.common.SketchesArgumentException; |
| import org.apache.datasketches.common.Util; |
| import org.testng.annotations.Test; |
| |
| /** |
| * @author eshcar |
| */ |
| public class ConcurrentHeapQuickSelectSketchTest { |
| |
| |
| @Test(expectedExceptions = SketchesArgumentException.class) |
| public void checkBadSerVer() { |
| final int lgK = 9; |
| final int k = 1 << lgK; |
| final int u = k; |
| final SharedLocal sl = new SharedLocal(lgK); |
| final UpdatableThetaSketch shared = sl.shared; |
| final UpdatableThetaSketch local = sl.local; |
| |
| assertTrue(local.isEmpty()); |
| |
| for (int i = 0; i< u; i++) { |
| local.update(i); |
| } |
| waitForBgPropagationToComplete(shared); |
| |
| assertFalse(local.isEmpty()); |
| assertEquals(local.getEstimate(), u, 0.0); |
| assertEquals(shared.getRetainedEntries(false), u); |
| |
| final byte[] serArr = shared.toByteArray(); |
| final MemorySegment seg = MemorySegment.ofArray(serArr); |
| final ThetaSketch sk = ThetaSketch.heapify(seg, sl.seed); |
| assertTrue(sk instanceof HeapQuickSelectSketch); //Intentional promotion to Parent |
| |
| seg.set(JAVA_BYTE, SER_VER_BYTE, (byte) 0); //corrupt the SerVer byte |
| ThetaSketch.heapify(seg, sl.seed); |
| } |
| |
| @Test |
| public void checkPropagationNotOrdered() { |
| final int lgK = 8; |
| final int k = 1 << lgK; |
| final int u = 200*k; |
| final SharedLocal sl = new SharedLocal(lgK, 4, false, false); |
| final UpdatableThetaSketch shared = sl.shared; |
| final UpdatableThetaSketch local = sl.local; |
| assertEquals((sl.bldr.getConCurLgNominalEntries()), 4); |
| assertTrue(local.isEmpty()); |
| |
| for (int i = 0; i < u; i++) { |
| local.update(i); |
| } |
| waitForBgPropagationToComplete(shared); |
| |
| assertFalse(local.isEmpty()); |
| assertTrue(shared.getRetainedEntries(true) <= u); |
| } |
| |
| @Test(expectedExceptions = SketchesArgumentException.class) |
| public void checkIllegalSketchID_UpdateSketch() { |
| final int lgK = 9; |
| final int k = 1 << lgK; |
| final int u = k; |
| final SharedLocal sl = new SharedLocal(lgK); |
| |
| final UpdatableThetaSketch shared = sl.shared; |
| final UpdatableThetaSketch local = sl.local; |
| assertTrue(local.isEmpty()); |
| assertTrue(shared instanceof ConcurrentHeapQuickSelectSketch); |
| for (int i = 0; i< u; i++) { |
| local.update(i); |
| } |
| assertTrue(shared.compact().isCompact()); |
| |
| assertFalse(local.isEmpty()); |
| assertEquals(local.getEstimate(), u, 0.0); |
| assertEquals(shared.getRetainedEntries(false), u); |
| final byte[] byteArray = shared.toByteArray(); |
| final MemorySegment seg = MemorySegment.ofArray(byteArray); |
| seg.set(JAVA_BYTE, FAMILY_BYTE, (byte) 0); //corrupt the FamilyID byte |
| |
| //try to heapify the corrupted seg |
| ThetaSketch.heapify(seg, sl.seed); |
| } |
| |
| @Test(expectedExceptions = SketchesArgumentException.class) |
| public void checkHeapifySeedConflict() { |
| final int lgK = 9; |
| final long seed = 1021; |
| final long seed2 = Util.DEFAULT_UPDATE_SEED; |
| final SharedLocal sl = new SharedLocal(lgK, lgK, seed); |
| final byte[] byteArray = sl.shared.toByteArray(); |
| final MemorySegment srcSeg = MemorySegment.ofArray(byteArray); |
| ThetaSketch.heapify(srcSeg, seed2); |
| } |
| |
| @Test(expectedExceptions = SketchesArgumentException.class) |
| public void checkHeapifyCorruptLgNomLongs() { |
| final int lgK = 4; |
| final SharedLocal sl = new SharedLocal(lgK); |
| final byte[] serArr = sl.shared.toByteArray(); |
| final MemorySegment srcSeg = MemorySegment.ofArray(serArr); |
| srcSeg.set(JAVA_BYTE, LG_NOM_LONGS_BYTE, (byte)2); //corrupt |
| ThetaSketch.heapify(srcSeg, Util.DEFAULT_UPDATE_SEED); |
| } |
| |
| @Test(expectedExceptions = UnsupportedOperationException.class) |
| public void checkIllegalHashUpdate() { |
| final int lgK = 4; |
| final SharedLocal sl = new SharedLocal(lgK); |
| sl.shared.hashUpdate(1); |
| } |
| |
| @Test |
| public void checkHeapifyByteArrayExact() { |
| final int lgK = 9; |
| final int k = 1 << lgK; |
| final int u = k; |
| final SharedLocal sl = new SharedLocal(lgK); |
| UpdatableThetaSketch shared = sl.shared; |
| final UpdatableThetaSketch local = sl.local; |
| |
| for (int i=0; i<u; i++) { |
| local.update(i); |
| } |
| waitForBgPropagationToComplete(shared); |
| |
| final byte[] serArr = shared.toByteArray(); |
| final MemorySegment srcSeg = MemorySegment.ofArray(serArr).asReadOnly(); |
| final ThetaSketch recoveredShared = UpdatableThetaSketch.heapify(srcSeg); |
| |
| //reconstruct to Native/Direct |
| final int bytes = ThetaSketch.getMaxUpdateSketchBytes(k); |
| final MemorySegment wseg = MemorySegment.ofArray(new byte[bytes]); |
| shared = sl.bldr.buildSharedFromSketch((UpdatableThetaSketch)recoveredShared, wseg); |
| final UpdatableThetaSketch local2 = sl.bldr.buildLocal(shared); |
| |
| assertEquals(local2.getEstimate(), u, 0.0); |
| assertEquals(local2.getLowerBound(2), u, 0.0); |
| assertEquals(local2.getUpperBound(2), u, 0.0); |
| assertFalse(local2.isEmpty()); |
| assertFalse(local2.isEstimationMode()); |
| assertEquals(local2.getResizeFactor(), local.getResizeFactor()); |
| local2.toString(true, true, 8, true); |
| } |
| |
| @Test |
| public void checkHeapifyByteArrayEstimating() { |
| final int lgK = 12; |
| final int k = 1 << lgK; |
| final int u = 2*k; |
| |
| final SharedLocal sl = new SharedLocal(lgK); |
| final UpdatableThetaSketch local = sl.local; |
| UpdatableThetaSketch shared = sl.shared; |
| |
| for (int i=0; i<u; i++) { |
| local.update(i); |
| } |
| waitForBgPropagationToComplete(shared); |
| |
| final double localEst = local.getEstimate(); |
| final double localLB = local.getLowerBound(2); |
| final double localUB = local.getUpperBound(2); |
| assertTrue(local.isEstimationMode()); |
| final byte[] serArr = shared.toByteArray(); |
| |
| final MemorySegment srcSeg = MemorySegment.ofArray(serArr).asReadOnly(); |
| final UpdatableThetaSketch recoveredShared = UpdatableThetaSketch.heapify(srcSeg, sl.seed); |
| |
| final int bytes = ThetaSketch.getMaxUpdateSketchBytes(k); |
| final MemorySegment wseg = MemorySegment.ofArray(new byte[bytes]); |
| shared = sl.bldr.buildSharedFromSketch(recoveredShared, wseg); |
| final UpdatableThetaSketch local2 = sl.bldr.buildLocal(shared); |
| assertEquals(local2.getEstimate(), localEst); |
| assertEquals(local2.getLowerBound(2), localLB); |
| assertEquals(local2.getUpperBound(2), localUB); |
| assertFalse(local2.isEmpty()); |
| assertTrue(local2.isEstimationMode()); |
| assertEquals(local2.getResizeFactor(), local.getResizeFactor()); |
| } |
| |
| @Test |
| public void checkHeapifyMemorySegmentEstimating() { |
| final int lgK = 9; |
| final int k = 1 << lgK; |
| final int u = 2*k; //thus estimating |
| |
| final SharedLocal sl = new SharedLocal(lgK); |
| final UpdatableThetaSketch local = sl.local; |
| UpdatableThetaSketch shared = sl.shared; |
| |
| for (int i=0; i<u; i++) { |
| local.update(i); |
| } |
| waitForBgPropagationToComplete(shared); |
| |
| final double localEst = local.getEstimate(); |
| final double localLB = local.getLowerBound(2); |
| final double localUB = local.getUpperBound(2); |
| assertTrue(local.isEstimationMode()); |
| assertFalse(local.isOffHeap()); |
| assertFalse(local.hasMemorySegment()); |
| |
| final byte[] serArr = shared.toByteArray(); |
| |
| final MemorySegment srcSeg = MemorySegment.ofArray(serArr).asReadOnly(); |
| final UpdatableThetaSketch recoveredShared = UpdatableThetaSketch.heapify(srcSeg, Util.DEFAULT_UPDATE_SEED); |
| |
| final int bytes = ThetaSketch.getMaxUpdateSketchBytes(k); |
| final MemorySegment wseg = MemorySegment.ofArray(new byte[bytes]); |
| shared = sl.bldr.buildSharedFromSketch(recoveredShared, wseg); |
| final UpdatableThetaSketch local2 = sl.bldr.buildLocal(shared); |
| |
| assertEquals(local2.getEstimate(), localEst); |
| assertEquals(local2.getLowerBound(2), localLB); |
| assertEquals(local2.getUpperBound(2), localUB); |
| assertEquals(local2.isEmpty(), false); |
| assertTrue(local2.isEstimationMode()); |
| } |
| |
| @Test |
| public void checkHQStoCompactForms() { |
| final int lgK = 9; |
| final int k = 1 << lgK; |
| final int u = 4*k; //thus estimating |
| |
| final int maxBytes = (k << 4) + (Family.QUICKSELECT.getMinPreLongs() << 3); |
| |
| final SharedLocal sl = new SharedLocal(lgK); |
| final UpdatableThetaSketch shared = sl.shared; |
| final UpdatableThetaSketch local = sl.local; |
| |
| assertEquals(local.getClass().getSimpleName(), "ConcurrentHeapThetaBuffer"); |
| assertFalse(local.isOffHeap()); |
| assertFalse(local.hasMemorySegment()); |
| |
| for (int i=0; i<u; i++) { |
| local.update(i); |
| } |
| waitForBgPropagationToComplete(shared); |
| |
| shared.rebuild(); //forces size back to k |
| |
| //get baseline values |
| final double localEst = local.getEstimate(); |
| final double localLB = local.getLowerBound(2); |
| final double localUB = local.getUpperBound(2); |
| final int sharedBytes = shared.getCurrentBytes(); |
| final int sharedCompBytes = shared.getCompactBytes(); |
| assertEquals(sharedBytes, maxBytes); |
| assertTrue(local.isEstimationMode()); |
| |
| CompactThetaSketch comp1, comp2, comp3, comp4; |
| |
| comp1 = shared.compact(false, null); |
| |
| assertEquals(comp1.getEstimate(), localEst); |
| assertEquals(comp1.getLowerBound(2), localLB); |
| assertEquals(comp1.getUpperBound(2), localUB); |
| assertEquals(comp1.isEmpty(), false); |
| assertTrue(comp1.isEstimationMode()); |
| assertEquals(comp1.getCompactBytes(), sharedCompBytes); |
| assertEquals(comp1.getClass().getSimpleName(), "HeapCompactSketch"); |
| |
| comp2 = shared.compact(true, null); |
| |
| assertEquals(comp2.getEstimate(), localEst); |
| assertEquals(comp2.getLowerBound(2), localLB); |
| assertEquals(comp2.getUpperBound(2), localUB); |
| assertEquals(comp2.isEmpty(), false); |
| assertTrue(comp2.isEstimationMode()); |
| assertEquals(comp2.getCompactBytes(), sharedCompBytes); |
| assertEquals(comp2.getClass().getSimpleName(), "HeapCompactSketch"); |
| |
| final byte[] segArr2 = new byte[sharedCompBytes]; |
| final MemorySegment seg2 = MemorySegment.ofArray(segArr2); //allocate seg for compact form |
| |
| comp3 = shared.compact(false, seg2); //load the seg2 |
| |
| assertEquals(comp3.getEstimate(), localEst); |
| assertEquals(comp3.getLowerBound(2), localLB); |
| assertEquals(comp3.getUpperBound(2), localUB); |
| assertEquals(comp3.isEmpty(), false); |
| assertTrue(comp3.isEstimationMode()); |
| assertEquals(comp3.getCompactBytes(), sharedCompBytes); |
| assertEquals(comp3.getClass().getSimpleName(), "DirectCompactSketch"); |
| |
| Util.clear(seg2); |
| comp4 = shared.compact(true, seg2); |
| |
| assertEquals(comp4.getEstimate(), localEst); |
| assertEquals(comp4.getLowerBound(2), localLB); |
| assertEquals(comp4.getUpperBound(2), localUB); |
| assertEquals(comp4.isEmpty(), false); |
| assertTrue(comp4.isEstimationMode()); |
| assertEquals(comp4.getCompactBytes(), sharedCompBytes); |
| assertEquals(comp4.getClass().getSimpleName(), "DirectCompactSketch"); |
| comp4.toString(false, true, 0, false); |
| } |
| |
| @Test |
| public void checkHQStoCompactEmptyForms() { |
| final int lgK = 9; |
| final SharedLocal sl = new SharedLocal(lgK); |
| final UpdatableThetaSketch shared = sl.shared; |
| final UpdatableThetaSketch local = sl.local; |
| println("lgArr: "+ local.getLgArrLongs()); |
| |
| //empty |
| local.toString(false, true, 0, false); |
| final boolean estimating = false; |
| assertTrue(local instanceof ConcurrentHeapThetaBuffer); |
| final double localEst = local.getEstimate(); |
| final double localLB = local.getLowerBound(2); |
| final double localUB = local.getUpperBound(2); |
| //int currentUSBytes = local.getCurrentBytes(false); |
| //assertEquals(currentUSBytes, (32*8) + 24); // clumsy, but a function of RF and TCF |
| final int compBytes = local.getCompactBytes(); //compact form |
| assertEquals(compBytes, 8); |
| assertEquals(local.isEstimationMode(), estimating); |
| |
| final byte[] arr2 = new byte[compBytes]; |
| final MemorySegment seg2 = MemorySegment.ofArray(arr2); |
| |
| final CompactThetaSketch csk2 = shared.compact(false, seg2); |
| assertEquals(csk2.getEstimate(), localEst); |
| assertEquals(csk2.getLowerBound(2), localLB); |
| assertEquals(csk2.getUpperBound(2), localUB); |
| assertEquals(csk2.isEmpty(), true); |
| assertEquals(csk2.isEstimationMode(), estimating); |
| assertTrue(csk2.isOrdered()); |
| |
| final CompactThetaSketch csk3 = shared.compact(true, seg2); |
| csk3.toString(false, true, 0, false); |
| csk3.toString(); |
| assertEquals(csk3.getEstimate(), localEst); |
| assertEquals(csk3.getLowerBound(2), localLB); |
| assertEquals(csk3.getUpperBound(2), localUB); |
| assertEquals(csk3.isEmpty(), true); |
| assertEquals(csk3.isEstimationMode(), estimating); |
| assertTrue(csk3.isOrdered()); |
| } |
| |
| @Test |
| public void checkExactMode() { |
| final int lgK = 12; |
| final int u = 1 << lgK; |
| final SharedLocal sl = new SharedLocal(lgK); |
| final UpdatableThetaSketch shared = sl.shared; |
| final UpdatableThetaSketch local = sl.local; |
| |
| assertTrue(local.isEmpty()); |
| |
| for (int i = 0; i< u; i++) { |
| local.update(i); |
| } |
| waitForBgPropagationToComplete(shared); |
| |
| assertEquals(local.getEstimate(), u, 0.0); |
| assertEquals(shared.getRetainedEntries(false), u); |
| } |
| |
| @Test |
| public void checkEstMode() { |
| final int lgK = 12; |
| final int k = 1 << lgK; |
| final SharedLocal sl = new SharedLocal(lgK); |
| final UpdatableThetaSketch shared = sl.shared; |
| final UpdatableThetaSketch local = sl.local; |
| |
| assertTrue(local.isEmpty()); |
| |
| final int u = 3*k; |
| for (int i = 0; i< u; i++) { |
| local.update(i); |
| } |
| waitForBgPropagationToComplete(shared); |
| final int retained = shared.getRetainedEntries(false); |
| assertTrue(retained > k); |
| // it could be exactly k, but in this case must be greater |
| } |
| |
| @Test |
| public void checkErrorBounds() { |
| final int lgK = 9; |
| final int k = 1 << lgK; |
| final SharedLocal sl = new SharedLocal(lgK); |
| final UpdatableThetaSketch local = sl.local; |
| final UpdatableThetaSketch shared = sl.shared; |
| |
| //Exact mode |
| //int limit = (int)ConcurrentSharedThetaSketch.computeExactLimit(lim, 0); //? ask Eshcar |
| for (int i = 0; i < k; i++ ) { |
| local.update(i); |
| } |
| |
| double est = local.getEstimate(); |
| double lb = local.getLowerBound(2); |
| double ub = local.getUpperBound(2); |
| assertEquals(est, ub, 0.0); |
| assertEquals(est, lb, 0.0); |
| |
| //Est mode |
| final int u = 2 * k; |
| for (int i = k; i < u; i++ ) { |
| local.update(i); |
| local.update(i); //test duplicate rejection |
| } |
| waitForBgPropagationToComplete(shared); |
| est = local.getEstimate(); |
| lb = local.getLowerBound(2); |
| ub = local.getUpperBound(2); |
| assertTrue(est <= ub); |
| assertTrue(est >= lb); |
| } |
| |
| @Test |
| public void checkRebuild() { |
| final int lgK = 4; |
| final int k = 1 << lgK; |
| final SharedLocal sl = new SharedLocal(lgK); |
| //must build shared first |
| final UpdatableThetaSketch shared = sl.shared; |
| final UpdatableThetaSketch local = sl.local; |
| |
| assertTrue(local.isEmpty()); |
| final int t = ((ConcurrentHeapThetaBuffer)local).getHashTableThreshold(); |
| |
| for (int i = 0; i< t; i++) { |
| local.update(i); |
| } |
| waitForBgPropagationToComplete(shared); |
| |
| assertFalse(local.isEmpty()); |
| assertTrue(local.getEstimate() > 0.0); |
| assertTrue(shared.getRetainedEntries(false) > k); |
| |
| shared.rebuild(); |
| assertEquals(shared.getRetainedEntries(false), k); |
| assertEquals(shared.getRetainedEntries(true), k); |
| shared.rebuild(); |
| assertEquals(shared.getRetainedEntries(false), k); |
| assertEquals(shared.getRetainedEntries(true), k); |
| } |
| |
| @Test |
| public void checkBuilder() { |
| final int lgK = 4; |
| final SharedLocal sl = new SharedLocal(lgK); |
| assertEquals(sl.bldr.getConCurLgNominalEntries(), lgK); |
| assertEquals(sl.bldr.getLgNominalEntries(), lgK); |
| println(sl.bldr.toString()); |
| } |
| |
| @Test(expectedExceptions = SketchesArgumentException.class) |
| public void checkBuilderSmallNominal() { |
| final int lgK = 2; //too small |
| new SharedLocal(lgK); |
| } |
| |
| @Test(expectedExceptions = SketchesArgumentException.class) |
| public void checkNegativeHashes() { |
| final int lgK = 9; |
| final SharedLocal sl = new SharedLocal(lgK); |
| final UpdatableThetaSketch local = sl.local; |
| local.hashUpdate(-1L); |
| } |
| |
| @Test |
| public void checkResetAndStartingSubMultiple() { |
| final int lgK = 9; |
| final int k = 1 << lgK; |
| final SharedLocal sl = new SharedLocal(lgK); |
| final UpdatableThetaSketch shared = sl.shared; |
| final UpdatableThetaSketch local = sl.local; |
| |
| assertTrue(local.isEmpty()); |
| final int u = 3*k; |
| |
| for (int i = 0; i< u; i++) { local.update(i); } |
| waitForBgPropagationToComplete(shared); |
| |
| assertFalse(local.isEmpty()); |
| assertTrue(shared.getRetainedEntries(false) >= k); |
| assertTrue(local.getThetaLong() < Long.MAX_VALUE); |
| |
| shared.reset(); |
| local.reset(); |
| assertTrue(local.isEmpty()); |
| assertEquals(shared.getRetainedEntries(false), 0); |
| assertEquals(local.getEstimate(), 0.0, 0.0); |
| assertEquals(local.getThetaLong(), Long.MAX_VALUE); |
| } |
| |
| @Test |
| public void checkDQStoCompactEmptyForms() { |
| final int lgK = 9; |
| final SharedLocal sl = new SharedLocal(lgK); |
| final UpdatableThetaSketch local = sl.local; |
| final UpdatableThetaSketch shared = sl.shared; |
| |
| //empty |
| local.toString(false, true, 0, false); //exercise toString |
| assertTrue(local instanceof ConcurrentHeapThetaBuffer); |
| final double localEst = local.getEstimate(); |
| final double localLB = local.getLowerBound(2); |
| final double uskUB = local.getUpperBound(2); |
| assertFalse(local.isEstimationMode()); |
| |
| final int bytes = local.getCompactBytes(); |
| assertEquals(bytes, 8); |
| final byte[] segArr2 = new byte[bytes]; |
| final MemorySegment seg2 = MemorySegment.ofArray(segArr2); |
| |
| final CompactThetaSketch csk2 = shared.compact(false, seg2); |
| assertEquals(csk2.getEstimate(), localEst); |
| assertEquals(csk2.getLowerBound(2), localLB); |
| assertEquals(csk2.getUpperBound(2), uskUB); |
| assertTrue(csk2.isEmpty()); |
| assertFalse(csk2.isEstimationMode()); |
| assertTrue(csk2.isOrdered()); |
| |
| final CompactThetaSketch csk3 = shared.compact(true, seg2); |
| csk3.toString(false, true, 0, false); |
| csk3.toString(); |
| assertEquals(csk3.getEstimate(), localEst); |
| assertEquals(csk3.getLowerBound(2), localLB); |
| assertEquals(csk3.getUpperBound(2), uskUB); |
| assertTrue(csk3.isEmpty()); |
| assertFalse(csk3.isEstimationMode()); |
| assertTrue(csk2.isOrdered()); |
| } |
| |
| @Test(expectedExceptions = SketchesArgumentException.class) |
| public void checkMinReqBytes() { |
| final int lgK = 4; |
| final int k = 1 << lgK; |
| final SharedLocal sl = new SharedLocal(lgK); |
| for (int i = 0; i < (4 * k); i++) { sl.local.update(i); } |
| waitForBgPropagationToComplete(sl.shared); |
| final byte[] byteArray = sl.shared.toByteArray(); |
| final byte[] badBytes = Arrays.copyOfRange(byteArray, 0, 24); //corrupt no. bytes |
| final MemorySegment seg = MemorySegment.ofArray(badBytes).asReadOnly(); |
| ThetaSketch.heapify(seg); |
| } |
| |
| @Test(expectedExceptions = SketchesArgumentException.class) |
| public void checkThetaAndLgArrLongs() { |
| final int lgK = 4; |
| final int k = 1 << lgK; |
| final SharedLocal sl = new SharedLocal(lgK); |
| for (int i = 0; i < k; i++) { sl.local.update(i); } |
| waitForBgPropagationToComplete(sl.shared); |
| final byte[] badArray = sl.shared.toByteArray(); |
| final MemorySegment seg = MemorySegment.ofArray(badArray); |
| PreambleUtil.insertLgArrLongs(seg, 4); //corrupt |
| PreambleUtil.insertThetaLong(seg, Long.MAX_VALUE / 2); //corrupt |
| ThetaSketch.heapify(seg); |
| } |
| |
| @Test |
| public void checkFamily() { |
| final SharedLocal sl = new SharedLocal(); |
| final UpdatableThetaSketch local = sl.local; |
| assertEquals(local.getFamily(), Family.QUICKSELECT); |
| } |
| |
| @Test |
| public void checkBackgroundPropagation() { |
| final int lgK = 4; |
| final int k = 1 << lgK; |
| final int u = 5*k; |
| final SharedLocal sl = new SharedLocal(lgK); |
| assertTrue(sl.local.isEmpty()); |
| |
| int i = 0; |
| for (; i < k; i++) { sl.local.update(i); } //exact |
| waitForBgPropagationToComplete(sl.shared); |
| |
| assertFalse(sl.local.isEmpty()); |
| assertTrue(sl.local.getEstimate() > 0.0); |
| final long theta1 = sl.sharedIf.getVolatileTheta(); |
| |
| for (; i < u; i++) { sl.local.update(i); } //continue, make it estimating |
| waitForBgPropagationToComplete(sl.shared); |
| |
| final long theta2 = sl.sharedIf.getVolatileTheta(); |
| final int entries = sl.shared.getRetainedEntries(false); |
| assertTrue((entries > k) || (theta2 < theta1), |
| "entries= " + entries + " k= " + k + " theta1= " + theta1 + " theta2= " + theta2); |
| |
| sl.shared.rebuild(); |
| assertEquals(sl.shared.getRetainedEntries(false), k); |
| assertEquals(sl.shared.getRetainedEntries(true), k); |
| sl.local.rebuild(); |
| assertEquals(sl.shared.getRetainedEntries(false), k); |
| assertEquals(sl.shared.getRetainedEntries(true), k); |
| } |
| |
| @Test |
| public void checkBuilderExceptions() { |
| final UpdatableThetaSketchBuilder bldr = new UpdatableThetaSketchBuilder(); |
| try { |
| bldr.setNominalEntries(8); |
| fail(); |
| } catch (final SketchesArgumentException e) { } |
| try { |
| bldr.setConCurNominalEntries(8); |
| fail(); |
| } catch (final SketchesArgumentException e) { } |
| try { |
| bldr.setConCurLogNominalEntries(3); |
| fail(); |
| } catch (final SketchesArgumentException e) { } |
| bldr.setNumPoolThreads(4); |
| assertEquals(bldr.getNumPoolThreads(), 4); |
| bldr.setMaxConcurrencyError(0.04); |
| assertEquals(bldr.getMaxConcurrencyError(), 0.04); |
| bldr.setMaxNumLocalThreads(4); |
| assertEquals(bldr.getMaxNumLocalThreads(), 4); |
| } |
| |
| @Test(expectedExceptions = UnsupportedOperationException.class) |
| public void checkToByteArray() { |
| final SharedLocal sl = new SharedLocal(); |
| sl.local.toByteArray(); |
| } |
| |
| @Test |
| public void printlnTest() { |
| println("PRINTING: "+this.getClass().getName()); |
| } |
| |
| /** |
| * @param s value to print |
| */ |
| static void println(final String s) { |
| //System.out.println(s); //disable here |
| } |
| |
| static class SharedLocal { |
| static final long DefaultSeed = Util.DEFAULT_UPDATE_SEED; |
| final UpdatableThetaSketch shared; |
| final ConcurrentSharedThetaSketch sharedIf; |
| final UpdatableThetaSketch local; |
| final int sharedLgK; |
| final int localLgK; |
| final long seed; |
| final MemorySegment wseg; |
| final UpdatableThetaSketchBuilder bldr = new UpdatableThetaSketchBuilder(); |
| |
| SharedLocal() { |
| this(9, 9, DefaultSeed, false, true, 1); |
| } |
| |
| SharedLocal(final int lgK) { |
| this(lgK, lgK, DefaultSeed, false, true, 1); |
| } |
| |
| SharedLocal(final int sharedLgK, final int localLgK) { |
| this(sharedLgK, localLgK, DefaultSeed, false, true, 1); |
| } |
| |
| SharedLocal(final int sharedLgK, final int localLgK, final long seed) { |
| this(sharedLgK, localLgK, seed, false, true, 1); |
| } |
| |
| SharedLocal(final int sharedLgK, final int localLgK, final boolean useSeg) { |
| this(sharedLgK, localLgK, DefaultSeed, useSeg, true, 1); |
| } |
| |
| SharedLocal(final int sharedLgK, final int localLgK, final boolean useSeg, final boolean ordered) { |
| this(sharedLgK, localLgK, DefaultSeed, useSeg, ordered, 1); |
| } |
| |
| SharedLocal(final int sharedLgK, final int localLgK, final long seed, final boolean useSeg, final boolean ordered, final int segMult) { |
| this.sharedLgK = sharedLgK; |
| this.localLgK = localLgK; |
| this.seed = seed; |
| if (useSeg) { |
| final int bytes = (((4 << sharedLgK) * segMult) + (Family.QUICKSELECT.getMaxPreLongs())) << 3; |
| wseg = MemorySegment.ofArray(new byte[bytes]); |
| } else { |
| wseg = null; |
| } |
| bldr.setLogNominalEntries(sharedLgK); |
| bldr.setConCurLogNominalEntries(localLgK); |
| bldr.setPropagateOrderedCompact(ordered); |
| bldr.setSeed(this.seed); |
| shared = bldr.buildShared(wseg); |
| local = bldr.buildLocal(shared); |
| sharedIf = (ConcurrentSharedThetaSketch) shared; |
| } |
| } |
| |
| static void waitForBgPropagationToComplete(final UpdatableThetaSketch shared) { |
| try { |
| Thread.sleep(10); |
| } catch (final InterruptedException e) { |
| e.printStackTrace(); |
| } |
| final ConcurrentSharedThetaSketch csts = (ConcurrentSharedThetaSketch)shared; |
| csts.awaitBgPropagationTermination(); |
| ConcurrentPropagationService.resetExecutorService(Thread.currentThread().getId()); |
| csts.initBgPropagationService(); |
| } |
| |
| } |