| /* |
| * 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 org.apache.datasketches.common.Util.LS; |
| import static org.apache.datasketches.common.Util.TAB; |
| import static org.apache.datasketches.common.Util.ceilingPowerOf2; |
| |
| import java.lang.foreign.MemorySegment; |
| |
| import org.apache.datasketches.common.Family; |
| import org.apache.datasketches.common.MemorySegmentRequest; |
| import org.apache.datasketches.common.ResizeFactor; |
| import org.apache.datasketches.common.SketchesArgumentException; |
| import org.apache.datasketches.common.SketchesStateException; |
| import org.apache.datasketches.common.SuppressFBWarnings; |
| import org.apache.datasketches.common.Util; |
| import org.apache.datasketches.thetacommon.ThetaUtil; |
| |
| /** |
| * For building a new UpdatableThetaSketch. |
| * |
| * @author Lee Rhodes |
| */ |
| public final class UpdatableThetaSketchBuilder { |
| private int bLgNomLongs; |
| private long bSeed; |
| private ResizeFactor bRF; |
| private Family bFam; |
| private float bP; |
| private MemorySegmentRequest bMemorySegmentRequest; |
| |
| //Fields for concurrent theta sketch |
| private int bNumPoolThreads; |
| private int bConCurLgNomLongs; |
| private boolean bPropagateOrderedCompact; |
| private double bMaxConcurrencyError; |
| private int bMaxNumLocalThreads; |
| |
| /** |
| * Constructor for building a new UpdatableThetaSketch. The default configuration is |
| * <ul> |
| * <li>Nominal Entries: {@value org.apache.datasketches.thetacommon.ThetaUtil#DEFAULT_NOMINAL_ENTRIES}</li> |
| * <li>Seed: {@value org.apache.datasketches.common.Util#DEFAULT_UPDATE_SEED}</li> |
| * <li>Resize Factor: The default for sketches on the Java heap is {@link ResizeFactor#X8}. |
| * For direct sketches, which are targeted for off-heap, this value will |
| * be fixed at either {@link ResizeFactor#X1} or {@link ResizeFactor#X2}.</li> |
| * <li>Family: {@link org.apache.datasketches.common.Family#QUICKSELECT}</li> |
| * <li>Input Sampling Probability, p: 1.0</li> |
| * <li>MemorySegmentRequest implementation: null</li> |
| * </ul> |
| * Parameters unique to the concurrent sketches only: |
| * <ul> |
| * <li>Concurrent NumPoolThreads: 3</li> |
| * <li>Number of local Nominal Entries: 4</li> |
| * <li>Concurrent PropagateOrderedCompact: true</li> |
| * <li>Concurrent MaxConcurrencyError: 0</li> |
| * <li>Concurrent MaxNumLocalThreads: 1</li> |
| * </ul> |
| */ |
| public UpdatableThetaSketchBuilder() { |
| bLgNomLongs = Integer.numberOfTrailingZeros(ThetaUtil.DEFAULT_NOMINAL_ENTRIES); |
| bSeed = Util.DEFAULT_UPDATE_SEED; |
| bRF = ResizeFactor.X8; |
| bFam = Family.QUICKSELECT; |
| bP = (float) 1.0; |
| bMemorySegmentRequest = null; |
| |
| // Default values for concurrent sketch |
| bNumPoolThreads = ConcurrentPropagationService.NUM_POOL_THREADS; |
| bConCurLgNomLongs = 4; //default is smallest legal QS sketch |
| bPropagateOrderedCompact = true; |
| bMaxConcurrencyError = 0; |
| bMaxNumLocalThreads = 1; |
| } |
| |
| /** |
| * Sets the local Nominal Entries for this builder. |
| * This value is also used for building a shared concurrent sketch. |
| * The minimum value is 16 (2^4) and the maximum value is 67,108,864 (2^26). |
| * Be aware that sketches as large as this maximum value may not have been |
| * thoroughly tested or characterized for performance. |
| * |
| * @param nomEntries <a href="{@docRoot}/resources/dictionary.html#nomEntries">Nominal Entries</a> |
| * This will become the ceiling power of 2 if the given value is not. |
| * @return this UpdatableThetaSketchBuilder |
| */ |
| public UpdatableThetaSketchBuilder setNominalEntries(final int nomEntries) { |
| bLgNomLongs = ThetaUtil.checkNomLongs(nomEntries); |
| return this; |
| } |
| |
| /** |
| * Alternative method of setting the local Nominal Entries for this builder from the log_base2 value. |
| * This value is also used for building a shared concurrent sketch. |
| * The minimum value is 4 and the maximum value is 26. |
| * Be aware that sketches as large as this maximum value may not have been |
| * thoroughly characterized for performance. |
| * |
| * @param lgNomEntries the Log Nominal Entries. Also for the concurrent shared sketch |
| * @return this UpdatableThetaSketchBuilder |
| */ |
| public UpdatableThetaSketchBuilder setLogNominalEntries(final int lgNomEntries) { |
| bLgNomLongs = ThetaUtil.checkNomLongs(1 << lgNomEntries); |
| return this; |
| } |
| |
| /** |
| * Alternative method of setting the Nominal Entries for this builder from the log_base2 value, commonly called LgK. |
| * This value is also used for building a shared concurrent sketch. |
| * The minimum value is 4 and the maximum value is 26. |
| * Be aware that sketches as large as 26 may not have been |
| * thoroughly characterized for performance. |
| * |
| * @param lgK the Log Nominal Entries. Also for the concurrent shared sketch. |
| * @return this UpdatableThetaSketchBuilder |
| */ |
| public UpdatableThetaSketchBuilder setLgK(final int lgK) { |
| bLgNomLongs = ThetaUtil.checkNomLongs(1 << lgK); |
| return this; |
| } |
| |
| /** |
| * Returns the local Log-base 2 Nominal Entries |
| * @return Log-base 2 Nominal Entries |
| */ |
| public int getLgNominalEntries() { |
| return bLgNomLongs; |
| } |
| |
| /** |
| * Sets the local (default) Concurrent Nominal Entries for the concurrent local sketch. The minimum value is 16 and the |
| * maximum value is 67,108,864, which is 2^26. |
| * Be aware that sketches as large as this maximum |
| * value have not been thoroughly tested or characterized for performance. |
| * |
| * @param nomEntries <a href="{@docRoot}/resources/dictionary.html#nomEntries">Nominal Entries</a> |
| * This will become the ceiling power of 2 if it is not. |
| * @return this UpdatableThetaSketchBuilder |
| */ |
| public UpdatableThetaSketchBuilder setConCurNominalEntries(final int nomEntries) { |
| bConCurLgNomLongs = Integer.numberOfTrailingZeros(ceilingPowerOf2(nomEntries)); |
| if (bConCurLgNomLongs > ThetaUtil.MAX_LG_NOM_LONGS || bConCurLgNomLongs < ThetaUtil.MIN_LG_NOM_LONGS) { |
| throw new SketchesArgumentException( |
| "Nominal Entries must be >= 16 and <= 67108864: " + nomEntries); |
| } |
| return this; |
| } |
| |
| /** |
| * Alternative method of setting the local (default) Nominal Entries for a local concurrent sketch from the log_base2 value. |
| * The minimum value is 4 and the maximum value is 26. |
| * Be aware that sketches as large as this maximum |
| * value have not been thoroughly tested or characterized for performance. |
| * |
| * @param lgNomEntries the Log Nominal Entries for a concurrent local sketch |
| * @return this UpdatableThetaSketchBuilder |
| */ |
| public UpdatableThetaSketchBuilder setConCurLogNominalEntries(final int lgNomEntries) { |
| bConCurLgNomLongs = lgNomEntries; |
| if (bConCurLgNomLongs > ThetaUtil.MAX_LG_NOM_LONGS || bConCurLgNomLongs < ThetaUtil.MIN_LG_NOM_LONGS) { |
| throw new SketchesArgumentException( |
| "Log Nominal Entries must be >= 4 and <= 26: " + lgNomEntries); |
| } |
| return this; |
| } |
| |
| /** |
| * Returns local Log-base 2 Nominal Entries for the concurrent local sketch |
| * @return Log-base 2 Nominal Entries for the concurrent local sketch |
| */ |
| public int getConCurLgNominalEntries() { |
| return bConCurLgNomLongs; |
| } |
| |
| /** |
| * Sets the local long seed value that is required by the hashing function. |
| * @param seed <a href="{@docRoot}/resources/dictionary.html#seed">See seed</a> |
| * @return this UpdatableThetaSketchBuilder |
| */ |
| public UpdatableThetaSketchBuilder setSeed(final long seed) { |
| bSeed = seed; |
| return this; |
| } |
| |
| /** |
| * Returns the local long seed value that is required by the hashing function. |
| * @return the seed |
| */ |
| public long getSeed() { |
| return bSeed; |
| } |
| |
| /** |
| * Sets the local upfront uniform pre-sampling probability, <i>p</i> |
| * @param p <a href="{@docRoot}/resources/dictionary.html#p">See Sampling Probability, <i>p</i></a> |
| * @return this UpdatableThetaSketchBuilder |
| */ |
| public UpdatableThetaSketchBuilder setP(final float p) { |
| if (p <= 0.0 || p > 1.0) { |
| throw new SketchesArgumentException("p must be > 0 and <= 1.0: " + p); |
| } |
| bP = p; |
| return this; |
| } |
| |
| /** |
| * Returns the local upfront uniform pre-sampling probability <i>p</i> |
| * @return the pre-sampling probability <i>p</i> |
| */ |
| public float getP() { |
| return bP; |
| } |
| |
| /** |
| * Sets the local cache Resize Factor. |
| * @param rf <a href="{@docRoot}/resources/dictionary.html#resizeFactor">See Resize Factor</a> |
| * @return this UpdatableThetaSketchBuilder |
| */ |
| public UpdatableThetaSketchBuilder setResizeFactor(final ResizeFactor rf) { |
| bRF = rf; |
| return this; |
| } |
| |
| /** |
| * Returns the local Resize Factor |
| * @return the Resize Factor |
| */ |
| public ResizeFactor getResizeFactor() { |
| return bRF; |
| } |
| |
| /** |
| * Set the local Family. Choose either Family.ALPHA or Family.QUICKSELECT. |
| * @param family the family for this builder |
| * @return this UpdatableThetaSketchBuilder |
| */ |
| public UpdatableThetaSketchBuilder setFamily(final Family family) { |
| bFam = family; |
| return this; |
| } |
| |
| /** |
| * Returns the local Family |
| * @return the Family |
| */ |
| public Family getFamily() { |
| return bFam; |
| } |
| |
| /** |
| * Sets the local MemorySegmentRequest |
| * @param mSegReq the given MemorySegmentRequest |
| * @return this UpdatableThetaSketchBuilder |
| */ |
| public UpdatableThetaSketchBuilder setMemorySegmentRequest(final MemorySegmentRequest mSegReq) { |
| bMemorySegmentRequest = mSegReq; |
| return this; |
| } |
| |
| /** |
| * Returns the local MemorySegmentRequest |
| * @return the local MemorySegmentRequest |
| */ |
| public MemorySegmentRequest getMemorySegmentRequest() { |
| return bMemorySegmentRequest; |
| } |
| |
| //Concurrent related |
| |
| /** |
| * Sets the local number of pool threads used for background propagation in the concurrent sketches. |
| * @param numPoolThreads the given number of pool threads |
| */ |
| public void setNumPoolThreads(final int numPoolThreads) { |
| bNumPoolThreads = numPoolThreads; |
| } |
| |
| /** |
| * Gets the local number of background pool threads used for propagation in the concurrent sketches. |
| * @return the number of background pool threads |
| */ |
| public int getNumPoolThreads() { |
| return bNumPoolThreads; |
| } |
| |
| /** |
| * Sets the local Propagate Ordered Compact flag to the given value. Used with concurrent sketches. |
| * |
| * @param prop the given value |
| * @return this UpdatableThetaSketchBuilder |
| */ |
| public UpdatableThetaSketchBuilder setPropagateOrderedCompact(final boolean prop) { |
| bPropagateOrderedCompact = prop; |
| return this; |
| } |
| |
| /** |
| * Gets the local Propagate Ordered Compact flag used with concurrent sketches. |
| * @return the Propagate Ordered Compact flag |
| */ |
| public boolean getPropagateOrderedCompact() { |
| return bPropagateOrderedCompact; |
| } |
| |
| /** |
| * Sets the local Maximum Concurrency Error. |
| * @param maxConcurrencyError the given Maximum Concurrency Error. |
| */ |
| public void setMaxConcurrencyError(final double maxConcurrencyError) { |
| bMaxConcurrencyError = maxConcurrencyError; |
| } |
| |
| /** |
| * Gets the local Maximum Concurrency Error |
| * @return the Maximum Concurrency Error |
| */ |
| public double getMaxConcurrencyError() { |
| return bMaxConcurrencyError; |
| } |
| |
| /** |
| * Sets the local Maximum Number of Local Threads. |
| * This is used to set the size of the local concurrent buffers. |
| * @param maxNumLocalThreads the given Maximum Number of Local Threads |
| */ |
| public void setMaxNumLocalThreads(final int maxNumLocalThreads) { |
| bMaxNumLocalThreads = maxNumLocalThreads; |
| } |
| |
| /** |
| * Gets the local Maximum Number of Local Threads. |
| * @return the Maximum Number of Local Threads. |
| */ |
| public int getMaxNumLocalThreads() { |
| return bMaxNumLocalThreads; |
| } |
| |
| // BUILD FUNCTIONS |
| |
| /** |
| * Returns an UpdatableThetaSketch with the current configuration of this Builder. |
| * @return an UpdatableThetaSketch |
| */ |
| public UpdatableThetaSketch build() { |
| return build(null); |
| } |
| |
| /** |
| * Returns an UpdatableThetaSketch with the current configuration of this Builder |
| * with the specified backing destination MemorySegment store. |
| * Note: this can only be used with the QUICKSELECT Family of sketches |
| * and cannot be used with the Alpha Family of sketches. |
| * @param dstSeg The destination MemorySegment. |
| * @return an UpdatableThetaSketch |
| */ |
| public UpdatableThetaSketch build(final MemorySegment dstSeg) { |
| UpdatableThetaSketch sketch = null; |
| final boolean unionGadget = false; |
| switch (bFam) { |
| case ALPHA: { |
| if (dstSeg == null) { |
| sketch = HeapAlphaSketch.newHeapInstance(bLgNomLongs, bSeed, bP, bRF); |
| } |
| else { |
| throw new SketchesArgumentException("AlphaSketch cannot be backed by a MemorySegment."); |
| } |
| break; |
| } |
| case QUICKSELECT: { |
| if (dstSeg == null) { |
| sketch = new HeapQuickSelectSketch(bLgNomLongs, bSeed, bP, bRF, unionGadget); |
| } |
| else { |
| sketch = new DirectQuickSelectSketch(bLgNomLongs, bSeed, bP, bRF, dstSeg, bMemorySegmentRequest, unionGadget); |
| } |
| break; |
| } |
| default: { |
| throw new SketchesArgumentException( |
| "Given Family cannot be built as an UpdatableThetaSketch: " + bFam.toString()); |
| } |
| } |
| return sketch; |
| } |
| |
| /** |
| * Returns an on-heap concurrent shared UpdatableThetaSketch with the current configuration of the |
| * Builder. |
| * |
| * <p>The parameters unique to the shared concurrent sketch are: |
| * <ul> |
| * <li>Number of Pool Threads (default is 3)</li> |
| * <li>Maximum Concurrency Error</li> |
| * </ul> |
| * |
| * <p>Key parameters that are in common with other <i>ThetaSketches</i>: |
| * <ul> |
| * <li>Nominal Entries or Log Nominal Entries (for the shared concurrent sketch)</li> |
| * </ul> |
| * |
| * @return an on-heap concurrent UpdatableThetaSketch with the current configuration of the Builder. |
| */ |
| public UpdatableThetaSketch buildShared() { |
| return buildShared(null); |
| } |
| |
| /** |
| * Returns a concurrent shared UpdatableThetaSketch with the current |
| * configuration of the Builder and the given destination MemorySegment. If the destination |
| * MemorySegment is null, this defaults to an on-heap concurrent shared UpdatableThetaSketch. |
| * |
| * <p>The parameters unique to the shared concurrent sketch are: |
| * <ul> |
| * <li>Number of Pool Threads (default is 3)</li> |
| * <li>Maximum Concurrency Error</li> |
| * </ul> |
| * |
| * <p>Key parameters that are in common with other <i>Theta</i> sketches: |
| * <ul> |
| * <li>Nominal Entries or Log Nominal Entries (for the shared concurrent sketch)</li> |
| * <li>Destination MemorySegment (if not null, returned sketch is Direct. Default is null.)</li> |
| * </ul> |
| * |
| * @param dstSeg the given MemorySegment for Direct, otherwise <i>null</i>. |
| * @return a concurrent UpdatableThetaSketch with the current configuration of the Builder |
| * and the given destination MemorySegment. |
| */ |
| @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", |
| justification = "Harmless in Builder, fix later") |
| public UpdatableThetaSketch buildShared(final MemorySegment dstSeg) { |
| ConcurrentPropagationService.NUM_POOL_THREADS = bNumPoolThreads; |
| if (dstSeg == null) { |
| return new ConcurrentHeapQuickSelectSketch(bLgNomLongs, bSeed, bMaxConcurrencyError); |
| } else { |
| return new ConcurrentDirectQuickSelectSketch(bLgNomLongs, bSeed, bMaxConcurrencyError, dstSeg); |
| } |
| } |
| |
| /** |
| * Returns a direct (potentially off-heap) concurrent shared UpdatableThetaSketch with the current |
| * configuration of the Builder, the data from the given sketch, and the given destination |
| * MemorySegment. If the destination MemorySegment is null, this defaults to an on-heap |
| * concurrent shared UpdatableThetaSketch. |
| * |
| * <p>The parameters unique to the shared concurrent sketch are: |
| * <ul> |
| * <li>Number of Pool Threads (default is 3)</li> |
| * <li>Maximum Concurrency Error</li> |
| * </ul> |
| * |
| * <p>Key parameters that are in common with other <i>Theta</i> sketches: |
| * <ul> |
| * <li>Nominal Entries or Log Nominal Entries (for the shared concurrent sketch)</li> |
| * <li>Destination MemorySegment (if not null, returned sketch is Direct. Default is null.)</li> |
| * </ul> |
| * |
| * @param sketch a given UpdatableThetaSketch from which the data is used to initialize the returned |
| * shared sketch. |
| * @param dstSeg the given MemorySegment for Direct, otherwise <i>null</i>. |
| * @return a concurrent UpdatableThetaSketch with the current configuration of the Builder |
| * and the given destination MemorySegment. |
| */ |
| @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", |
| justification = "Harmless in Builder, fix later") |
| public UpdatableThetaSketch buildSharedFromSketch(final UpdatableThetaSketch sketch, final MemorySegment dstSeg) { |
| ConcurrentPropagationService.NUM_POOL_THREADS = bNumPoolThreads; |
| if (dstSeg == null) { |
| return new ConcurrentHeapQuickSelectSketch(sketch, bSeed, bMaxConcurrencyError); |
| } else { |
| return new ConcurrentDirectQuickSelectSketch(sketch, bSeed, bMaxConcurrencyError, dstSeg); |
| } |
| } |
| |
| /** |
| * Returns a local, on-heap, concurrent UpdatableThetaSketch to be used as a per-thread local buffer |
| * along with the given concurrent shared UpdatableThetaSketch and the current configuration of this |
| * Builder. |
| * |
| * <p>The parameters unique to the local concurrent sketch are: |
| * <ul> |
| * <li>Local Nominal Entries or Local Log Nominal Entries</li> |
| * <li>Propagate Ordered Compact flag</li> |
| * </ul> |
| * |
| * @param shared the concurrent shared sketch to be accessed via the concurrent local sketch. |
| * @return an UpdatableThetaSketch to be used as a per-thread local buffer. |
| */ |
| public UpdatableThetaSketch buildLocal(final UpdatableThetaSketch shared) { |
| if (shared == null || !(shared instanceof ConcurrentSharedThetaSketch)) { |
| throw new SketchesStateException("The concurrent shared sketch must be built first."); |
| } |
| return new ConcurrentHeapThetaBuffer(bConCurLgNomLongs, bSeed, |
| (ConcurrentSharedThetaSketch) shared, bPropagateOrderedCompact, bMaxNumLocalThreads); |
| } |
| |
| @Override |
| public String toString() { |
| final StringBuilder sb = new StringBuilder(); |
| sb.append("UpdatableThetaSketchBuilder configuration:").append(LS); |
| sb.append("LgK:").append(TAB).append(bLgNomLongs).append(LS); |
| sb.append("K:").append(TAB).append(1 << bLgNomLongs).append(LS); |
| sb.append("LgLocalK:").append(TAB).append(bConCurLgNomLongs).append(LS); |
| sb.append("LocalK:").append(TAB).append(1 << bConCurLgNomLongs).append(LS); |
| sb.append("Seed:").append(TAB).append(bSeed).append(LS); |
| sb.append("p:").append(TAB).append(bP).append(LS); |
| sb.append("ResizeFactor:").append(TAB).append(bRF).append(LS); |
| sb.append("Family:").append(TAB).append(bFam).append(LS); |
| sb.append("Propagate Ordered Compact").append(TAB).append(bPropagateOrderedCompact).append(LS); |
| sb.append("NumPoolThreads").append(TAB).append(bNumPoolThreads).append(LS); |
| sb.append("MaxConcurrencyError").append(TAB).append(bMaxConcurrencyError).append(LS); |
| sb.append("MaxNumLocalThreads").append(TAB).append(bMaxNumLocalThreads).append(LS); |
| return sb.toString(); |
| } |
| |
| } |