From fe9c382ef05dbe6f89d30fbbebb52a436faffdcc Mon Sep 17 00:00:00 2001 From: Larry Booker Date: Wed, 1 Jun 2022 07:58:38 -0700 Subject: [PATCH] Implement Open Addressing to support AsOfJoin (#2396) * implemented static and incremental OA hashing for asOf joings --- engine/table/build.gradle | 8 +- .../engine/table/impl/AsOfJoinHelper.java | 87 +- .../RightIncrementalAsOfJoinStateManager.java | 33 + ...ncrementalChunkedAsOfJoinStateManager.java | 59 +- .../impl/StaticAsOfJoinStateManager.java | 32 + .../StaticChunkedAsOfJoinStateManager.java | 100 +- ...rementalAsOfJoinStateManagerTypedBase.java | 933 ++++++++++++++++++ ...IncrementalHashedAsOfJoinStateManager.java | 91 ++ .../StaticAsOfJoinStateManagerTypedBase.java | 402 ++++++++ .../StaticHashedAsOfJoinStateManager.java | 31 + .../impl/asofjoin/TypedAsOfJoinFactory.java | 181 ++++ .../RightIncrementalAsOfJoinHasherByte.java | 319 ++++++ .../RightIncrementalAsOfJoinHasherChar.java | 319 ++++++ .../RightIncrementalAsOfJoinHasherDouble.java | 319 ++++++ .../RightIncrementalAsOfJoinHasherFloat.java | 319 ++++++ .../RightIncrementalAsOfJoinHasherInt.java | 319 ++++++ .../RightIncrementalAsOfJoinHasherLong.java | 318 ++++++ .../RightIncrementalAsOfJoinHasherObject.java | 321 ++++++ .../RightIncrementalAsOfJoinHasherShort.java | 319 ++++++ .../rightincopen/gen/TypedHashDispatcher.java | 43 + .../gen/StaticAsOfJoinHasherByte.java | 181 ++++ .../gen/StaticAsOfJoinHasherChar.java | 181 ++++ .../gen/StaticAsOfJoinHasherDouble.java | 181 ++++ .../gen/StaticAsOfJoinHasherFloat.java | 181 ++++ .../gen/StaticAsOfJoinHasherInt.java | 181 ++++ .../gen/StaticAsOfJoinHasherLong.java | 180 ++++ .../gen/StaticAsOfJoinHasherObject.java | 181 ++++ .../gen/StaticAsOfJoinHasherShort.java | 181 ++++ .../staticopen/gen/TypedHashDispatcher.java | 43 + .../impl/by/typed/TypedHasherFactory.java | 89 +- .../join/BucketedChunkedAjMergedListener.java | 5 +- .../incopen/gen/TypedHashDispatcher.java | 45 +- .../rightincopen/gen/TypedHashDispatcher.java | 45 +- .../staticopen/gen/TypedHashDispatcher.java | 45 +- .../engine/table/impl/QueryTableAjTest.java | 17 +- .../replicators/ReplicateTypedHashers.java | 4 + 36 files changed, 6088 insertions(+), 205 deletions(-) create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/RightIncrementalAsOfJoinStateManager.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/StaticAsOfJoinStateManager.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/RightIncrementalAsOfJoinStateManagerTypedBase.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/RightIncrementalHashedAsOfJoinStateManager.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/StaticAsOfJoinStateManagerTypedBase.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/StaticHashedAsOfJoinStateManager.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/TypedAsOfJoinFactory.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherByte.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherChar.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherDouble.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherFloat.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherInt.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherLong.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherObject.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherShort.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/TypedHashDispatcher.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherByte.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherChar.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherDouble.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherFloat.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherInt.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherLong.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherObject.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherShort.java create mode 100644 engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/TypedHashDispatcher.java diff --git a/engine/table/build.gradle b/engine/table/build.gradle index a6269745df1..85fb61694ac 100644 --- a/engine/table/build.gradle +++ b/engine/table/build.gradle @@ -92,9 +92,11 @@ spotless { '**/incopenagg/gen/*.java', '**/staticagg/gen/*.java', '**/staticopenagg/gen/*.java', - '**/naturaljoin/staticopen/gen/*.java', - '**/naturaljoin/incopen/gen/*.java', - '**/naturaljoin/rightincopen/gen/*.java', + '**/naturaljoin/typed/staticopen/gen/*.java', + '**/naturaljoin/typed/incopen/gen/*.java', + '**/naturaljoin/typed/rightincopen/gen/*.java', + '**/asofjoin/typed/rightincopen/gen/*.java', + '**/asofjoin/typed/staticopen/gen/*.java', 'src/main/java/io/deephaven/engine/table/impl/SymbolTableCombiner.java', 'src/main/java/io/deephaven/libs/GroovyStaticImports.java', 'src/test/java/**/*Sample.java' diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/AsOfJoinHelper.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/AsOfJoinHelper.java index e40853fc455..6ffcdef83c4 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/AsOfJoinHelper.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/AsOfJoinHelper.java @@ -2,28 +2,36 @@ import io.deephaven.base.Pair; import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.*; import io.deephaven.chunk.attributes.Any; import io.deephaven.chunk.attributes.Values; -import io.deephaven.engine.rowset.RowSetFactory; -import io.deephaven.engine.table.*; -import io.deephaven.engine.rowset.*; +import io.deephaven.chunk.sized.SizedBooleanChunk; +import io.deephaven.chunk.sized.SizedChunk; +import io.deephaven.chunk.sized.SizedLongChunk; import io.deephaven.chunk.util.hashing.ChunkEquals; +import io.deephaven.configuration.Configuration; +import io.deephaven.engine.rowset.*; +import io.deephaven.engine.rowset.chunkattributes.RowKeys; +import io.deephaven.engine.table.*; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalHashedAsOfJoinStateManager; +import io.deephaven.engine.table.impl.asofjoin.StaticAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.asofjoin.StaticHashedAsOfJoinStateManager; +import io.deephaven.engine.table.impl.by.typed.TypedHasherFactory; import io.deephaven.engine.table.impl.join.BucketedChunkedAjMergedListener; import io.deephaven.engine.table.impl.join.JoinListenerRecorder; import io.deephaven.engine.table.impl.join.ZeroKeyChunkedAjMergedListener; import io.deephaven.engine.table.impl.sort.LongSortKernel; import io.deephaven.engine.table.impl.sources.*; -import io.deephaven.chunk.*; -import io.deephaven.chunk.sized.SizedBooleanChunk; -import io.deephaven.chunk.sized.SizedChunk; -import io.deephaven.chunk.sized.SizedLongChunk; import io.deephaven.engine.table.impl.ssa.ChunkSsaStamp; import io.deephaven.engine.table.impl.ssa.SegmentedSortedArray; import io.deephaven.engine.table.impl.ssa.SsaSsaStamp; -import io.deephaven.engine.table.impl.util.*; +import io.deephaven.engine.table.impl.util.RowRedirection; +import io.deephaven.engine.table.impl.util.SingleValueRowRedirection; +import io.deephaven.engine.table.impl.util.SizedSafeCloseable; +import io.deephaven.engine.table.impl.util.WritableRowRedirection; import io.deephaven.engine.table.impl.util.compact.CompactKernel; import io.deephaven.engine.table.impl.util.compact.LongCompactKernel; -import io.deephaven.engine.rowset.chunkattributes.RowKeys; import io.deephaven.util.SafeCloseable; import io.deephaven.util.SafeCloseableList; import org.apache.commons.lang3.mutable.MutableInt; @@ -34,6 +42,10 @@ import java.util.function.Supplier; public class AsOfJoinHelper { + static boolean USE_TYPED_STATE_MANAGER = + Configuration.getInstance().getBooleanWithDefault( + "AsOfJoinHelper.useTypedStateManager", + true); private AsOfJoinHelper() {} // static use only @@ -93,10 +105,12 @@ static Table asOfJoin(JoinControl control, QueryTable leftTable, QueryTable righ if (leftTable.isRefreshing()) { return bothIncrementalAj(control, leftTable, rightTable, columnsToMatch, columnsToAdd, order, disallowExactMatch, stampPair, - leftSources, rightSources, leftStampSource, rightStampSource, rowRedirection); + originalLeftSources, leftSources, rightSources, leftStampSource, originalRightStampSource, + rightStampSource, rowRedirection); } return rightTickingLeftStaticAj(control, leftTable, rightTable, columnsToMatch, columnsToAdd, order, - disallowExactMatch, stampPair, leftSources, rightSources, leftStampSource, rightStampSource, + disallowExactMatch, stampPair, originalLeftSources, leftSources, rightSources, leftStampSource, + originalRightStampSource, rightStampSource, rowRedirection); } else { return rightStaticAj(control, leftTable, rightTable, columnsToMatch, columnsToAdd, order, @@ -108,7 +122,7 @@ static Table asOfJoin(JoinControl control, QueryTable leftTable, QueryTable righ @NotNull private static Table rightStaticAj(JoinControl control, QueryTable leftTable, - Table rightTable, + QueryTable rightTable, MatchPair[] columnsToMatch, MatchPair[] columnsToAdd, SortingOrder order, @@ -121,6 +135,7 @@ private static Table rightStaticAj(JoinControl control, ColumnSource originalRightStampSource, ColumnSource rightStampSource, WritableRowRedirection rowRedirection) { + final LongArraySource slots = new LongArraySource(); final int slotCount; @@ -157,8 +172,23 @@ private static Table rightStaticAj(JoinControl control, leftGrouping = rightGrouping = null; } - final StaticChunkedAsOfJoinStateManager asOfJoinStateManager = - new StaticChunkedAsOfJoinStateManager(leftSources, size, originalLeftSources); + final StaticHashedAsOfJoinStateManager asOfJoinStateManager; + if (buildLeft) { + asOfJoinStateManager = USE_TYPED_STATE_MANAGER + ? TypedHasherFactory.make(StaticAsOfJoinStateManagerTypedBase.class, + leftSources, originalLeftSources, size, + control.getMaximumLoadFactor(), control.getTargetLoadFactor()) + : new StaticChunkedAsOfJoinStateManager(leftSources, + size, originalLeftSources); + } else { + asOfJoinStateManager = USE_TYPED_STATE_MANAGER + ? TypedHasherFactory.make(StaticAsOfJoinStateManagerTypedBase.class, + leftSources, originalLeftSources, size, + control.getMaximumLoadFactor(), control.getTargetLoadFactor()) + : new StaticChunkedAsOfJoinStateManager(leftSources, + size, originalLeftSources); + } + final Pair, ObjectArraySource> leftGroupedSources; final int leftGroupingSize; @@ -228,6 +258,8 @@ private static Table rightStaticAj(JoinControl control, arrayValuesCache = null; if (rightGroupedSources != null) { asOfJoinStateManager.convertRightGrouping(slots, slotCount, rightGroupedSources.getSecond()); + } else { + asOfJoinStateManager.convertRightBuildersToIndex(slots, slotCount); } } @@ -453,7 +485,7 @@ private static void processLeftSlotWithRightCache(AsOfStampContext stampContext, * If the asOfJoinStateManager is null, it means we are passing in the leftRowSet. If the leftRowSet is null; we are * passing in the asOfJoinStateManager and should obtain the leftRowSet from the state manager if necessary. */ - private static void getCachedLeftStampsAndKeys(RightIncrementalChunkedAsOfJoinStateManager asOfJoinStateManager, + private static void getCachedLeftStampsAndKeys(RightIncrementalHashedAsOfJoinStateManager asOfJoinStateManager, RowSet leftRowSet, ColumnSource leftStampSource, SizedSafeCloseable fillContext, @@ -517,9 +549,11 @@ private static Table rightTickingLeftStaticAj(JoinControl control, SortingOrder order, boolean disallowExactMatch, MatchPair stampPair, + ColumnSource[] originalLeftSources, ColumnSource[] leftSources, ColumnSource[] rightSources, ColumnSource leftStampSource, + ColumnSource originalRightStampSource, ColumnSource rightStampSource, WritableRowRedirection rowRedirection) { if (leftTable.isRefreshing()) { @@ -534,8 +568,12 @@ private static Table rightTickingLeftStaticAj(JoinControl control, final ChunkSsaStamp chunkSsaStamp = ChunkSsaStamp.make(stampChunkType, reverse); final int tableSize = control.initialBuildSize(); - final RightIncrementalChunkedAsOfJoinStateManager asOfJoinStateManager = - new RightIncrementalChunkedAsOfJoinStateManager(leftSources, tableSize); + + final RightIncrementalHashedAsOfJoinStateManager asOfJoinStateManager = USE_TYPED_STATE_MANAGER + ? TypedHasherFactory.make(RightIncrementalAsOfJoinStateManagerTypedBase.class, + leftSources, originalLeftSources, tableSize, + control.getMaximumLoadFactor(), control.getTargetLoadFactor()) + : new RightIncrementalChunkedAsOfJoinStateManager(leftSources, tableSize, originalLeftSources); final LongArraySource slots = new LongArraySource(); final int slotCount = asOfJoinStateManager.buildFromLeftSide(leftTable.getRowSet(), leftSources, slots); @@ -900,9 +938,11 @@ private static Table bothIncrementalAj(JoinControl control, SortingOrder order, boolean disallowExactMatch, MatchPair stampPair, + ColumnSource[] originalLeftSources, ColumnSource[] leftSources, ColumnSource[] rightSources, ColumnSource leftStampSource, + ColumnSource originalRightStampSource, ColumnSource rightStampSource, WritableRowRedirection rowRedirection) { final boolean reverse = order == SortingOrder.Descending; @@ -912,8 +952,13 @@ private static Table bothIncrementalAj(JoinControl control, SegmentedSortedArray.makeFactory(stampChunkType, reverse, control.rightSsaNodeSize()); final SsaSsaStamp ssaSsaStamp = SsaSsaStamp.make(stampChunkType, reverse); - final RightIncrementalChunkedAsOfJoinStateManager asOfJoinStateManager = - new RightIncrementalChunkedAsOfJoinStateManager(leftSources, control.initialBuildSize()); + final int tableSize = control.initialBuildSize(); + + final RightIncrementalHashedAsOfJoinStateManager asOfJoinStateManager = USE_TYPED_STATE_MANAGER + ? TypedHasherFactory.make(RightIncrementalAsOfJoinStateManagerTypedBase.class, + leftSources, originalLeftSources, tableSize, + control.getMaximumLoadFactor(), control.getTargetLoadFactor()) + : new RightIncrementalChunkedAsOfJoinStateManager(leftSources, tableSize, originalLeftSources); final LongArraySource slots = new LongArraySource(); int slotCount = asOfJoinStateManager.buildFromLeftSide(leftTable.getRowSet(), leftSources, slots); @@ -989,11 +1034,11 @@ public SegmentedSortedArray apply(RowSet leftIndex) { // them into an ssa final byte state = asOfJoinStateManager.getState(slot); if ((state - & RightIncrementalChunkedAsOfJoinStateManager.ENTRY_RIGHT_MASK) == RightIncrementalChunkedAsOfJoinStateManager.ENTRY_RIGHT_IS_EMPTY) { + & RightIncrementalHashedAsOfJoinStateManager.ENTRY_RIGHT_MASK) == RightIncrementalHashedAsOfJoinStateManager.ENTRY_RIGHT_IS_EMPTY) { continue; } if ((state - & RightIncrementalChunkedAsOfJoinStateManager.ENTRY_LEFT_MASK) == RightIncrementalChunkedAsOfJoinStateManager.ENTRY_LEFT_IS_EMPTY) { + & RightIncrementalHashedAsOfJoinStateManager.ENTRY_LEFT_MASK) == RightIncrementalHashedAsOfJoinStateManager.ENTRY_LEFT_IS_EMPTY) { continue; } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/RightIncrementalAsOfJoinStateManager.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/RightIncrementalAsOfJoinStateManager.java new file mode 100644 index 00000000000..22081a5ef1d --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/RightIncrementalAsOfJoinStateManager.java @@ -0,0 +1,33 @@ +package io.deephaven.engine.table.impl; + +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.RowSet; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.sources.LongSparseArraySource; +import io.deephaven.engine.table.impl.util.ContiguousWritableRowRedirection; +import io.deephaven.engine.table.impl.util.LongColumnSourceWritableRowRedirection; +import io.deephaven.engine.table.impl.util.WritableRowRedirection; +import io.deephaven.engine.table.impl.util.WritableRowRedirectionLockFree; + +import java.util.Arrays; +import java.util.Objects; +import java.util.function.LongUnaryOperator; +import java.util.stream.Collectors; + +public abstract class RightIncrementalAsOfJoinStateManager { + public static final long NO_RIGHT_ENTRY_VALUE = RowSequence.NULL_ROW_KEY; + + protected final ColumnSource[] keySourcesForErrorMessages; + + protected RightIncrementalAsOfJoinStateManager(ColumnSource[] keySourcesForErrorMessages) { + this.keySourcesForErrorMessages = keySourcesForErrorMessages; + } + + // produce a pretty key for error messages + protected String extractKeyStringFromSourceTable(long leftKey) { + if (keySourcesForErrorMessages.length == 1) { + return Objects.toString(keySourcesForErrorMessages[0].get(leftKey)); + } + return "[" + Arrays.stream(keySourcesForErrorMessages).map(ls -> Objects.toString(ls.get(leftKey))).collect(Collectors.joining(", ")) + "]"; + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/RightIncrementalChunkedAsOfJoinStateManager.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/RightIncrementalChunkedAsOfJoinStateManager.java index e5baea1034d..8551a1d89c2 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/RightIncrementalChunkedAsOfJoinStateManager.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/RightIncrementalChunkedAsOfJoinStateManager.java @@ -41,6 +41,7 @@ import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.mutable.MutableObject; import org.jetbrains.annotations.Nullable; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalHashedAsOfJoinStateManager; import java.util.function.Function; // endregion extra imports @@ -52,6 +53,7 @@ // endregion class visibility class RightIncrementalChunkedAsOfJoinStateManager // region extensions + extends RightIncrementalHashedAsOfJoinStateManager // endregion extensions { // region constants @@ -153,21 +155,6 @@ class RightIncrementalChunkedAsOfJoinStateManager // endmixin rehash // region extra variables - public static final byte ENTRY_RIGHT_MASK = 0x3; - public static final byte ENTRY_RIGHT_IS_EMPTY = 0x0; - public static final byte ENTRY_RIGHT_IS_BUILDER = 0x1; - public static final byte ENTRY_RIGHT_IS_SSA = 0x2; - public static final byte ENTRY_RIGHT_IS_INDEX = 0x3; - - public static final byte ENTRY_LEFT_MASK = 0x30; - public static final byte ENTRY_LEFT_IS_EMPTY = 0x00; - public static final byte ENTRY_LEFT_IS_BUILDER = 0x10; - public static final byte ENTRY_LEFT_IS_SSA = 0x20; - public static final byte ENTRY_LEFT_IS_INDEX = 0x30; - - private static final byte ENTRY_INITIAL_STATE_LEFT = ENTRY_LEFT_IS_BUILDER|ENTRY_RIGHT_IS_EMPTY; - private static final byte ENTRY_INITIAL_STATE_RIGHT = ENTRY_LEFT_IS_EMPTY|ENTRY_RIGHT_IS_BUILDER; - /** * We use our side source to originally build the RowSet using builders. When a state is activated (meaning we * have a corresponding entry for it on the other side); we'll turn it into an SSA. If we have updates for an @@ -193,9 +180,11 @@ class RightIncrementalChunkedAsOfJoinStateManager RightIncrementalChunkedAsOfJoinStateManager(ColumnSource[] tableKeySources , int tableSize // region constructor arguments + , ColumnSource[] tableKeySourcesForErrors // endregion constructor arguments ) { // region super + super(tableKeySourcesForErrors); // endregion super keyColumnCount = tableKeySources.length; @@ -281,7 +270,8 @@ private void ensureOverflowCapacity(WritableIntChunk chunkPositi } // region build wrappers - int buildFromLeftSide(RowSequence leftIndex, ColumnSource[] leftSources, @NotNull final LongArraySource addedSlots) { + @Override + public int buildFromLeftSide(RowSequence leftIndex, ColumnSource[] leftSources, @NotNull final LongArraySource addedSlots) { if (leftIndex.isEmpty()) { return 0; } @@ -292,7 +282,8 @@ int buildFromLeftSide(RowSequence leftIndex, ColumnSource[] leftSources, @Not } } - int buildFromRightSide(RowSequence rightIndex, ColumnSource[] rightSources, @NotNull final LongArraySource addedSlots, int usedSlots) { + @Override + public int buildFromRightSide(RowSequence rightIndex, ColumnSource[] rightSources, @NotNull final LongArraySource addedSlots, int usedSlots) { if (rightIndex.isEmpty()) { return usedSlots; } @@ -1462,14 +1453,17 @@ private long getCookie(LongArraySource cookieSource, long slot) { return cookie - cookieGeneration; } + @Override public int markForRemoval(RowSet restampRemovals, ColumnSource[] sources, LongArraySource slots, ObjectArraySource sequentialBuilders) { return accumulateIndices(restampRemovals, sources, slots, sequentialBuilders, true); } + @Override public int probeAdditions(RowSet restampAdditions, ColumnSource[] sources, LongArraySource slots, ObjectArraySource sequentialBuilders) { return accumulateIndices(restampAdditions, sources, slots, sequentialBuilders, false); } + @Override public int gatherShiftIndex(RowSet restampAdditions, ColumnSource[] sources, LongArraySource slots, ObjectArraySource sequentialBuilders) { return accumulateIndices(restampAdditions, sources, slots, sequentialBuilders, true); } @@ -1492,7 +1486,8 @@ private int accumulateIndices(RowSet restampAdditions, ColumnSource[] rightSo return slotCount.intValue(); } - void probeRightInitial(RowSequence rightIndex, ColumnSource[] rightSources) { + @Override + public void probeRightInitial(RowSequence rightIndex, ColumnSource[] rightSources) { if (rightIndex.isEmpty()) { return; } @@ -1501,15 +1496,6 @@ void probeRightInitial(RowSequence rightIndex, ColumnSource[] rightSources) } } - private void addToSequentialBuilder(long slot, @NotNull ObjectArraySource sequentialBuilders, long indexKey) { - RowSetBuilderSequential builder = sequentialBuilders.getUnsafe(slot); - if (builder == null) { - builder = RowSetFactory.builderSequential(); - sequentialBuilders.set(slot, builder); - } - builder.appendKey(indexKey); - } - // endregion probe wrappers // mixin decorationProbe @@ -1880,7 +1866,8 @@ public int getOverflowSize() { * @param slot the slot in the table (either positive for a main slot, or negative for overflow) * @return the WritableRowSet for this slot */ - WritableRowSet getAndClearLeftIndex(long slot) { + @Override + public WritableRowSet getAndClearLeftIndex(long slot) { final RowSetBuilderSequential builder; if (isOverflowLocation(slot)) { final long overflowLocation = hashLocationToOverflowLocation(slot); @@ -1896,6 +1883,7 @@ WritableRowSet getAndClearLeftIndex(long slot) { return builder.build(); } + @Override public byte getState(long slot) { if (isOverflowLocation(slot)) { final long overflowLocation = hashLocationToOverflowLocation(slot); @@ -1905,6 +1893,7 @@ public byte getState(long slot) { } } + @Override public SegmentedSortedArray getRightSsa(long slot, Function ssaFactory) { if (isOverflowLocation(slot)) { final long overflowLocation = hashLocationToOverflowLocation(slot); @@ -1935,6 +1924,7 @@ public SegmentedSortedArray getRightSsa(long slot, Function ssaFactory) { if (isOverflowLocation(slot)) { final long overflowLocation = hashLocationToOverflowLocation(slot); @@ -2093,6 +2087,7 @@ public SegmentedSortedArray getLeftSsa(long slot, Function indexOutput) { if (isOverflowLocation(slot)) { final long overflowLocation = hashLocationToOverflowLocation(slot); @@ -2106,10 +2101,6 @@ public SegmentedSortedArray getLeftSsaOrIndex(long slot, MutableObject> 4); - } - public SegmentedSortedArray getRightSsaOrIndex(long slot, MutableObject indexOutput) { if (isOverflowLocation(slot)) { final long overflowLocation = hashLocationToOverflowLocation(slot); @@ -2123,10 +2114,6 @@ public SegmentedSortedArray getRightSsaOrIndex(long slot, MutableObject indexOutput, long location, byte entryType, ObjectArraySource sideSource, ByteArraySource stateSource, byte stateValueForIndex) { switch (entryType) { diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/StaticAsOfJoinStateManager.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/StaticAsOfJoinStateManager.java new file mode 100644 index 00000000000..6d8613a4bd6 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/StaticAsOfJoinStateManager.java @@ -0,0 +1,32 @@ +package io.deephaven.engine.table.impl; + +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.RowSet; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.LongSparseArraySource; +import io.deephaven.engine.table.impl.util.ContiguousWritableRowRedirection; +import io.deephaven.engine.table.impl.util.LongColumnSourceWritableRowRedirection; +import io.deephaven.engine.table.impl.util.WritableRowRedirection; +import io.deephaven.engine.table.impl.util.WritableRowRedirectionLockFree; + +import java.util.Arrays; +import java.util.Objects; +import java.util.function.LongUnaryOperator; +import java.util.stream.Collectors; + +public abstract class StaticAsOfJoinStateManager { + protected final ColumnSource[] keySourcesForErrorMessages; + + protected StaticAsOfJoinStateManager(ColumnSource[] keySourcesForErrorMessages) { + this.keySourcesForErrorMessages = keySourcesForErrorMessages; + } + + // produce a pretty key for error messages + protected String extractKeyStringFromSourceTable(long leftKey) { + if (keySourcesForErrorMessages.length == 1) { + return Objects.toString(keySourcesForErrorMessages[0].get(leftKey)); + } + return "[" + Arrays.stream(keySourcesForErrorMessages).map(ls -> Objects.toString(ls.get(leftKey))).collect(Collectors.joining(", ")) + "]"; + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/StaticChunkedAsOfJoinStateManager.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/StaticChunkedAsOfJoinStateManager.java index 012feeb8939..ec11790acf2 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/StaticChunkedAsOfJoinStateManager.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/StaticChunkedAsOfJoinStateManager.java @@ -38,6 +38,7 @@ // region extra imports import org.apache.commons.lang3.mutable.MutableInt; +import io.deephaven.engine.table.impl.asofjoin.StaticHashedAsOfJoinStateManager; // endregion extra imports import static io.deephaven.util.SafeCloseable.closeArray; @@ -46,6 +47,7 @@ // endregion class visibility class StaticChunkedAsOfJoinStateManager // region extensions + extends StaticHashedAsOfJoinStateManager // endregion extensions { // region constants @@ -167,11 +169,12 @@ class StaticChunkedAsOfJoinStateManager StaticChunkedAsOfJoinStateManager(ColumnSource[] tableKeySources , int tableSize - // region constructor arguments - , ColumnSource[] tableKeySourcesForErrors + // region constructor arguments + , ColumnSource[] tableKeySourcesForErrors // endregion constructor arguments ) { // region super + super(tableKeySourcesForErrors); // endregion super keyColumnCount = tableKeySources.length; @@ -251,24 +254,26 @@ private void ensureOverflowCapacity(WritableIntChunk chunkPositi } // region build wrappers - int buildFromRightSide(RowSequence rightIndex, ColumnSource[] rightSources, @NotNull final LongArraySource addedSlots) { - if (rightIndex.isEmpty()) { + @Override + public int buildFromRightSide(RowSequence rightRowSet, ColumnSource[] rightSources, @NotNull final LongArraySource addedSlots) { + if (rightRowSet.isEmpty()) { return 0; } - try (final BuildContext bc = makeBuildContext(rightSources, rightIndex.size())) { + try (final BuildContext bc = makeBuildContext(rightSources, rightRowSet.size())) { final MutableInt slotCount = new MutableInt(0); - buildTable(bc, rightIndex, rightSources, false, addedSlots, slotCount); + buildTable(bc, rightRowSet, rightSources, false, addedSlots, slotCount); return slotCount.intValue(); } } - int buildFromLeftSide(RowSequence leftIndex, ColumnSource[] leftSources, @NotNull final LongArraySource addedSlots) { - if (leftIndex.isEmpty()) { + @Override + public int buildFromLeftSide(RowSequence leftRowSet, ColumnSource[] leftSources, @NotNull final LongArraySource addedSlots) { + if (leftRowSet.isEmpty()) { return 0; } - try (final BuildContext bc = makeBuildContext(leftSources, leftIndex.size())) { + try (final BuildContext bc = makeBuildContext(leftSources, leftRowSet.size())) { final MutableInt slotCount = new MutableInt(0); - buildTable(bc, leftIndex, leftSources, true, addedSlots, slotCount); + buildTable(bc, leftRowSet, leftSources, true, addedSlots, slotCount); return slotCount.intValue(); } } @@ -904,8 +909,8 @@ public void doRehash(BuildContext bc if (tableHashPivot == tableSize) { tableSize *= 2; ensureCapacity(tableSize); - // region rehash ensure capacity - buildCookieSource.ensureCapacity(tableSize); + // region rehash ensure capacity + buildCookieSource.ensureCapacity(tableSize); // endregion rehash ensure capacity } @@ -975,13 +980,13 @@ public void doRehash(BuildContext bc final byte stateValueToMove = stateSource.getUnsafe(oldHashLocation); stateSource.set(newHashLocation, stateValueToMove); stateSource.set(oldHashLocation, EMPTY_VALUE); - // region rehash move values + // region rehash move values - leftRowSetSource.set(newHashLocation, leftRowSetSource.get(oldHashLocation)); - leftRowSetSource.set(oldHashLocation, null); + leftRowSetSource.set(newHashLocation, leftRowSetSource.get(oldHashLocation)); + leftRowSetSource.set(oldHashLocation, null); - rightRowSetSource.set(newHashLocation, rightRowSetSource.get(oldHashLocation)); - rightRowSetSource.set(oldHashLocation, null); + rightRowSetSource.set(newHashLocation, rightRowSetSource.get(oldHashLocation)); + rightRowSetSource.set(oldHashLocation, null); final int cookie = buildCookieSource.getInt(oldHashLocation); addedSlots.set(cookie, newHashLocation); @@ -1060,13 +1065,13 @@ public void doRehash(BuildContext bc } bc.sourcePositions.add(ii); bc.destinationLocationPositionInWriteThrough.add((int)(tableLocation - firstBackingChunkLocation)); - // region promotion move - final long overflowLocation = bc.overflowLocationsAsKeyIndices.get(ii); - leftRowSetSource.set(tableLocation, overflowLeftRowSetSource.get(overflowLocation)); - overflowLeftRowSetSource.set(overflowLocation, null); + // region promotion move + final long overflowLocation = bc.overflowLocationsAsKeyIndices.get(ii); + leftRowSetSource.set(tableLocation, overflowLeftRowSetSource.get(overflowLocation)); + overflowLeftRowSetSource.set(overflowLocation, null); - rightRowSetSource.set(tableLocation, overflowRightRowSetSource.get(overflowLocation)); - overflowRightRowSetSource.set(overflowLocation, null); + rightRowSetSource.set(tableLocation, overflowRightRowSetSource.get(overflowLocation)); + overflowRightRowSetSource.set(overflowLocation, null); final int cookie = overflowBuildCookieSource.getInt(overflowLocation); addedSlots.set(cookie, tableLocation); @@ -1329,32 +1334,35 @@ private void getKeyChunks(ColumnSource[] sources, ColumnSource.GetContext[] c // region probe wrappers - void probeLeft(RowSequence leftIndex, ColumnSource[] leftSources) { - if (leftIndex.isEmpty()) { + @Override + public void probeLeft(RowSequence leftRowSet, ColumnSource[] leftSources) { + if (leftRowSet.isEmpty()) { return; } - try (final ProbeContext pc = makeProbeContext(leftSources, leftIndex.size())) { - decorationProbe(pc, leftIndex, leftSources, true, null, null, null); + try (final ProbeContext pc = makeProbeContext(leftSources, leftRowSet.size())) { + decorationProbe(pc, leftRowSet, leftSources, true, null, null,null); } } - int probeLeft(RowSequence leftIndex, ColumnSource[] leftSources, LongArraySource slots, RowSetBuilderRandom foundBuilder) { - if (leftIndex.isEmpty()) { + @Override + public int probeLeft(RowSequence leftRowSet, ColumnSource[] leftSources, LongArraySource slots, RowSetBuilderRandom foundBuilder) { + if (leftRowSet.isEmpty()) { return 0; } - try (final ProbeContext pc = makeProbeContext(leftSources, leftIndex.size())) { + try (final ProbeContext pc = makeProbeContext(leftSources, leftRowSet.size())) { final MutableInt slotCount = new MutableInt(); - decorationProbe(pc, leftIndex, leftSources, true, slots, slotCount, foundBuilder); + decorationProbe(pc, leftRowSet, leftSources, true, slots, slotCount, foundBuilder); return slotCount.intValue(); } } - void probeRight(RowSequence rightIndex, ColumnSource[] rightSources) { - if (rightIndex.isEmpty()) { + @Override + public void probeRight(RowSequence rightRowSet, ColumnSource[] rightSources) { + if (rightRowSet.isEmpty()) { return; } - try (final ProbeContext pc = makeProbeContext(rightSources, rightIndex.size())) { - decorationProbe(pc, rightIndex, rightSources, false, null, null, null); + try (final ProbeContext pc = makeProbeContext(rightSources, rightRowSet.size())) { + decorationProbe(pc, rightRowSet, rightSources, false, null, null, null); } } // endregion probe wrappers @@ -1697,11 +1705,13 @@ private int hashToTableLocation( } // region extraction functions - int getTableSize() { + @Override + public int getTableSize() { return tableSize; } - int getOverflowSize() { + @Override + public int getOverflowSize() { return nextOverflowLocation; } @@ -1716,7 +1726,8 @@ int getOverflowSize() { * @param slot the slot in the table (either positive for a main slot, or negative for overflow) * @return the RowSet for this slot */ - RowSet getLeftIndex(long slot) { + @Override + public RowSet getLeftIndex(long slot) { final RowSetBuilderSequential builder; if (isOverflowLocation(slot)) { final long overflowLocation = hashLocationToOverflowLocation(slot); @@ -1732,7 +1743,8 @@ RowSet getLeftIndex(long slot) { return builder.build(); } - void convertRightBuildersToIndex(LongArraySource slots, int slotCount) { + @Override + public void convertRightBuildersToIndex(LongArraySource slots, int slotCount) { for (int slotIndex = 0; slotIndex < slotCount; ++slotIndex) { final long slot = slots.getLong(slotIndex); if (isOverflowLocation(slot)) { @@ -1751,7 +1763,12 @@ void convertRightBuildersToIndex(LongArraySource slots, int slotCount) { rightBuildersConverted = true; } - void convertRightGrouping(LongArraySource slots, int slotCount, ObjectArraySource rowSetSource) { + protected String extractKeyStringFromSourceTable(long leftKey) { + return super.extractKeyStringFromSourceTable(leftKey); + } + + @Override + public void convertRightGrouping(LongArraySource slots, int slotCount, ObjectArraySource rowSetSource) { for (int slotIndex = 0; slotIndex < slotCount; ++slotIndex) { final long slot = slots.getLong(slotIndex); if (isOverflowLocation(slot)) { @@ -1778,7 +1795,8 @@ private RowSet getGroupedIndex(ObjectArraySource rowSetSource, RowSetBui return rowSetSource.getUnsafe(groupedRowSet.get(0)); } - RowSet getRightIndex(long slot) { + @Override + public RowSet getRightIndex(long slot) { if (rightBuildersConverted) { if (isOverflowLocation(slot)) { final long overflowLocation = hashLocationToOverflowLocation(slot); diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/RightIncrementalAsOfJoinStateManagerTypedBase.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/RightIncrementalAsOfJoinStateManagerTypedBase.java new file mode 100644 index 00000000000..414749f1ee0 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/RightIncrementalAsOfJoinStateManagerTypedBase.java @@ -0,0 +1,933 @@ +package io.deephaven.engine.table.impl.asofjoin; + +import io.deephaven.base.verify.Assert; +import io.deephaven.base.verify.Require; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.ChunkType; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.engine.rowset.*; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.WritableColumnSource; +import io.deephaven.engine.table.impl.by.alternatingcolumnsource.AlternatingColumnSource; +import io.deephaven.engine.table.impl.sources.InMemoryColumnSource; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.ObjectArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableByteArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableLongArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableObjectArraySource; +import io.deephaven.engine.table.impl.ssa.SegmentedSortedArray; +import io.deephaven.engine.table.impl.util.TypedHasherUtil; +import io.deephaven.engine.table.impl.util.TypedHasherUtil.BuildOrProbeContext.ProbeContext; +import io.deephaven.util.QueryConstants; +import org.apache.commons.lang3.mutable.MutableInt; +import org.apache.commons.lang3.mutable.MutableObject; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; + +import static io.deephaven.engine.table.impl.util.TypedHasherUtil.getKeyChunks; +import static io.deephaven.engine.table.impl.util.TypedHasherUtil.getPrevKeyChunks; + +public abstract class RightIncrementalAsOfJoinStateManagerTypedBase extends RightIncrementalHashedAsOfJoinStateManager { + public static final int CHUNK_SIZE = 4096; + private static final long MAX_TABLE_SIZE = 1 << 30; // maximum array size + + public static final byte ENTRY_EMPTY_STATE = QueryConstants.NULL_BYTE; + + // the number of slots in our table + protected int tableSize; + + // the number of slots in our alternate table, to start with "1" is a lie, but rehashPointer is zero; so our + // location value is positive and can be compared against rehashPointer safely + protected int alternateTableSize = 1; + + // how much of the alternate sources are necessary to rehash? + protected int rehashPointer = 0; + + protected long numEntries = 0; + + // the table will be rehashed to a load factor of targetLoadFactor if our loadFactor exceeds maximumLoadFactor + // or if it falls below minimum load factor we will instead contract the table + private final double maximumLoadFactor; + + // the keys for our hash entries + protected final ChunkType[] chunkTypes; + protected WritableColumnSource[] mainKeySources; + protected WritableColumnSource[] alternateKeySources; + + /** + * We use our side source to originally build the RowSet using builders. When a state is activated (meaning we have + * a corresponding entry for it on the other side); we'll turn it into an SSA. If we have updates for an inactive + * state, then we turn it into a WritableRowSet. The entry state tells us what we have on each side, using a nibble + * for the left and a nibble for the right. + */ + protected ImmutableObjectArraySource leftRowSetSource; + protected ImmutableObjectArraySource alternateLeftRowSetSource; + protected ImmutableObjectArraySource rightRowSetSource; + protected ImmutableObjectArraySource alternateRightRowSetSource; + + protected ImmutableByteArraySource stateSource = new ImmutableByteArraySource(); + protected ImmutableByteArraySource alternateStateSource = new ImmutableByteArraySource(); + + // the mask for insertion into the main table (this is used so that we can identify whether a slot belongs to the + // main or alternate table) + protected int mainInsertMask = 0; + protected int alternateInsertMask = (int) AlternatingColumnSource.ALTERNATE_SWITCH_MASK; + + /** + * Each slot in the hash table has a 'cookie', which we reset by incrementing the cookie generation. The cookie + * allows us to index into an array source that is passed in for each operation; serving as an intrusive set of + * modified states (we'll add relevant indices in the probe/build to a RowSet builder). + */ + protected ImmutableLongArraySource mainCookieSource = new ImmutableLongArraySource(); + protected ImmutableLongArraySource alternateCookieSource; + protected long cookieGeneration; + protected int nextCookie; + + protected void resetCookie() { + cookieGeneration += (10 + nextCookie); + nextCookie = 0; + } + + protected long getCookieMain(long slot) { + return getCookie(mainCookieSource, slot); + } + + protected long getCookieAlternate(long slot) { + return getCookie(alternateCookieSource, slot); + } + + protected long getCookie(ImmutableLongArraySource cookieSource, long slot) { + long cookie = cookieSource.getUnsafe(slot); + if (cookie == QueryConstants.NULL_LONG || cookie < cookieGeneration) { + cookieSource.set(slot, cookie = cookieGeneration + nextCookie); + nextCookie++; + } + return cookie - cookieGeneration; + } + + protected long makeCookieMain(long slot) { + return makeCookie(mainCookieSource, slot); + } + + protected long makeCookie(ImmutableLongArraySource cookieSource, long slot) { + long cookie = cookieGeneration + nextCookie; + cookieSource.set(slot, cookie); + nextCookie++; + return cookie - cookieGeneration; + } + + protected void migrateCookie(long cookie, long destinationLocation, LongArraySource hashSlots) { + if (cookie >= cookieGeneration && cookie - cookieGeneration < nextCookie) { + hashSlots.set(cookie, destinationLocation | mainInsertMask); + mainCookieSource.set(destinationLocation, cookie); + } + } + + protected RightIncrementalAsOfJoinStateManagerTypedBase(ColumnSource[] tableKeySources, + ColumnSource[] keySourcesForErrorMessages, int tableSize, double maximumLoadFactor) { + // region super + super(keySourcesForErrorMessages); + // endregion super + + this.tableSize = tableSize; + Require.leq(tableSize, "tableSize", MAX_TABLE_SIZE); + Require.gtZero(tableSize, "tableSize"); + Require.eq(Integer.bitCount(tableSize), "Integer.bitCount(tableSize)", 1); + Require.inRange(maximumLoadFactor, 0.0, 0.95, "maximumLoadFactor"); + + // region constructor + mainKeySources = new WritableColumnSource[tableKeySources.length]; + alternateKeySources = new WritableColumnSource[tableKeySources.length]; + chunkTypes = new ChunkType[tableKeySources.length]; + leftRowSetSource = new ImmutableObjectArraySource<>(Object.class, null); + alternateLeftRowSetSource = new ImmutableObjectArraySource<>(Object.class, null); + rightRowSetSource = new ImmutableObjectArraySource<>(Object.class, null); + alternateRightRowSetSource = new ImmutableObjectArraySource<>(Object.class, null); + // endregion constructor + + for (int ii = 0; ii < tableKeySources.length; ++ii) { + chunkTypes[ii] = keySourcesForErrorMessages[ii].getChunkType(); + mainKeySources[ii] = InMemoryColumnSource.getImmutableMemoryColumnSource(tableSize, + tableKeySources[ii].getType(), tableKeySources[ii].getComponentType()); + } + + this.maximumLoadFactor = maximumLoadFactor; + + ensureCapacity(tableSize); + } + + private void ensureCapacity(int tableSize) { + for (WritableColumnSource mainKeySource : mainKeySources) { + mainKeySource.ensureCapacity(tableSize); + } + // region ensureCapacity + leftRowSetSource.ensureCapacity(tableSize); + rightRowSetSource.ensureCapacity(tableSize); + stateSource.ensureCapacity(tableSize); + mainCookieSource.ensureCapacity(tableSize); + // endregion ensureCapacity + } + + public static class BuildContext extends TypedHasherUtil.BuildOrProbeContext { + private BuildContext(ColumnSource[] buildSources, int chunkSize) { + super(buildSources, chunkSize); + } + + final MutableInt rehashCredits = new MutableInt(0); + } + + BuildContext makeBuildContext(ColumnSource[] buildSources, long maxSize) { + return new BuildContext(buildSources, (int) Math.min(CHUNK_SIZE, maxSize)); + } + + ProbeContext makeProbeContext(ColumnSource[] buildSources, long maxSize) { + return new ProbeContext(buildSources, (int) Math.min(CHUNK_SIZE, maxSize)); + } + + protected static void createBuilder(ImmutableObjectArraySource source, long location, + long keyToAdd) { + final RowSetBuilderSequential builder; + source.set(location, builder = RowSetFactory.builderSequential()); + builder.appendKey(keyToAdd); + } + + protected static void addToBuilder(ImmutableObjectArraySource source, long location, + long keyToAdd) { + source.getUnsafe(location).appendKey(keyToAdd); + } + + protected void addLeftIndex(long tableLocation, long keyToAdd, byte currentState) { + final boolean isEmpty = (currentState & ENTRY_LEFT_MASK) == ENTRY_LEFT_IS_EMPTY; + if (isEmpty) { + final byte newState = (byte) ((currentState & ENTRY_RIGHT_MASK) | ENTRY_LEFT_IS_BUILDER); + stateSource.set(tableLocation, newState); + // noinspection unchecked + createBuilder((ImmutableObjectArraySource) leftRowSetSource, tableLocation, keyToAdd); + } else { + // noinspection unchecked + addToBuilder((ImmutableObjectArraySource) leftRowSetSource, tableLocation, keyToAdd); + } + } + + protected void addRightIndex(long tableLocation, long keyToAdd, byte currentState) { + final boolean isEmpty = (currentState & ENTRY_RIGHT_MASK) == ENTRY_RIGHT_IS_EMPTY; + if (isEmpty) { + final byte newState = (byte) ((currentState & ENTRY_LEFT_MASK) | ENTRY_RIGHT_IS_BUILDER); + stateSource.set(tableLocation, newState); + // noinspection unchecked + createBuilder((ImmutableObjectArraySource) rightRowSetSource, tableLocation, keyToAdd); + } else { + // noinspection unchecked + addToBuilder((ImmutableObjectArraySource) rightRowSetSource, tableLocation, keyToAdd); + } + } + + protected void addAlternateLeftIndex(long tableLocation, long keyToAdd, byte currentState) { + final boolean isEmpty = (currentState & ENTRY_LEFT_MASK) == ENTRY_LEFT_IS_EMPTY; + if (isEmpty) { + final byte newState = (byte) ((currentState & ENTRY_RIGHT_MASK) | ENTRY_LEFT_IS_BUILDER); + alternateStateSource.set(tableLocation, newState); + // noinspection unchecked + createBuilder((ImmutableObjectArraySource) alternateLeftRowSetSource, tableLocation, keyToAdd); + } else { + // noinspection unchecked + addToBuilder((ImmutableObjectArraySource) alternateLeftRowSetSource, tableLocation, keyToAdd); + } + } + + protected void addAlternateRightIndex(long tableLocation, long keyToAdd, byte currentState) { + final boolean isEmpty = (currentState & ENTRY_RIGHT_MASK) == ENTRY_RIGHT_IS_EMPTY; + if (isEmpty) { + final byte newState = (byte) ((currentState & ENTRY_LEFT_MASK) | ENTRY_RIGHT_IS_BUILDER); + alternateStateSource.set(tableLocation, newState); + // noinspection unchecked + createBuilder((ImmutableObjectArraySource) alternateRightRowSetSource, tableLocation, keyToAdd); + } else { + // noinspection unchecked + addToBuilder((ImmutableObjectArraySource) alternateRightRowSetSource, tableLocation, keyToAdd); + } + } + + protected void buildTable( + final boolean initialBuild, + final BuildContext bc, + final RowSequence buildRows, + final ColumnSource[] buildSources, + final LongArraySource hashSlots, + final TypedHasherUtil.BuildHandler buildHandler) { + try (final RowSequence.Iterator rsIt = buildRows.getRowSequenceIterator()) { + // noinspection unchecked + final Chunk[] sourceKeyChunks = new Chunk[buildSources.length]; + + while (rsIt.hasMore()) { + final RowSequence chunkOk = rsIt.getNextRowSequenceWithLength(bc.chunkSize); + + while (doRehash(initialBuild, bc.rehashCredits, chunkOk.intSize(), hashSlots)) { + migrateFront(hashSlots); + } + + getKeyChunks(buildSources, bc.getContexts, sourceKeyChunks, chunkOk); + + buildHandler.doBuild(chunkOk, sourceKeyChunks); + + bc.resetSharedContexts(); + } + } + } + + private class LeftBuildHandler implements TypedHasherUtil.BuildHandler { + final LongArraySource hashSlots; + final ObjectArraySource sequentialBuilders; + + private LeftBuildHandler(final LongArraySource hashSlots) { + this.hashSlots = hashSlots; + this.sequentialBuilders = null; + } + + private LeftBuildHandler(final LongArraySource hashSlots, + final ObjectArraySource sequentialBuilders) { + this.hashSlots = hashSlots; + this.sequentialBuilders = sequentialBuilders; + } + + @Override + public void doBuild(RowSequence chunkOk, Chunk[] sourceKeyChunks) { + hashSlots.ensureCapacity(nextCookie + chunkOk.intSize()); + buildFromLeftSide(chunkOk, sourceKeyChunks, hashSlots, sequentialBuilders); + } + } + + private class RightBuildHandler implements TypedHasherUtil.BuildHandler { + final LongArraySource hashSlots; + final ObjectArraySource sequentialBuilders; + + private RightBuildHandler(final LongArraySource hashSlots) { + this.hashSlots = hashSlots; + this.sequentialBuilders = null; + } + + private RightBuildHandler(final LongArraySource hashSlots, + final ObjectArraySource sequentialBuilders) { + this.hashSlots = hashSlots; + this.sequentialBuilders = sequentialBuilders; + } + + @Override + public void doBuild(RowSequence chunkOk, Chunk[] sourceKeyChunks) { + hashSlots.ensureCapacity(nextCookie + chunkOk.intSize()); + buildFromRightSide(chunkOk, sourceKeyChunks, hashSlots, sequentialBuilders); + } + } + + @Override + public int buildFromLeftSide(RowSequence leftRowSet, ColumnSource[] leftSources, + @NotNull final LongArraySource addedSlots) { + if (leftRowSet.isEmpty()) { + return 0; + } + try (final BuildContext bc = makeBuildContext(leftSources, leftRowSet.size())) { + int startCookie = nextCookie; + buildTable(true, bc, leftRowSet, leftSources, addedSlots, new LeftBuildHandler(addedSlots)); + return nextCookie - startCookie; + } + } + + @Override + public int buildFromRightSide(RowSequence rightRowSet, ColumnSource[] rightSources, + @NotNull final LongArraySource addedSlots, int usedSlots) { + if (rightRowSet.isEmpty()) { + return usedSlots; + } + try (final BuildContext bc = makeBuildContext(rightSources, rightRowSet.size())) { + int startCookie = nextCookie; + buildTable(true, bc, rightRowSet, rightSources, addedSlots, new RightBuildHandler(addedSlots)); + return usedSlots + (nextCookie - startCookie); + } + } + + @Override + public int markForRemoval(RowSet restampRemovals, ColumnSource[] sources, LongArraySource slots, + ObjectArraySource sequentialBuilders) { + return accumulateIndices(restampRemovals, sources, slots, sequentialBuilders, true); + } + + @Override + public int probeAdditions(RowSet restampAdditions, ColumnSource[] sources, LongArraySource slots, + ObjectArraySource sequentialBuilders) { + return accumulateIndices(restampAdditions, sources, slots, sequentialBuilders, false); + } + + @Override + public int gatherShiftIndex(RowSet restampAdditions, ColumnSource[] sources, LongArraySource slots, + ObjectArraySource sequentialBuilders) { + return accumulateIndices(restampAdditions, sources, slots, sequentialBuilders, true); + } + + public int gatherModifications(RowSet restampAdditions, ColumnSource[] sources, LongArraySource slots, + ObjectArraySource sequentialBuilders) { + return accumulateIndices(restampAdditions, sources, slots, sequentialBuilders, false); + } + + protected void probeTable( + final ProbeContext pc, + final RowSequence probeRows, + final boolean usePrev, + final ColumnSource[] probeSources, + final TypedHasherUtil.ProbeHandler handler) { + try (final RowSequence.Iterator rsIt = probeRows.getRowSequenceIterator()) { + // noinspection unchecked + final Chunk[] sourceKeyChunks = new Chunk[probeSources.length]; + + while (rsIt.hasMore()) { + final RowSequence chunkOk = rsIt.getNextRowSequenceWithLength(pc.chunkSize); + + if (usePrev) { + getPrevKeyChunks(probeSources, pc.getContexts, sourceKeyChunks, chunkOk); + } else { + getKeyChunks(probeSources, pc.getContexts, sourceKeyChunks, chunkOk); + } + + handler.doProbe(chunkOk, sourceKeyChunks); + + pc.resetSharedContexts(); + } + } + } + + private class RightProbeHandler implements TypedHasherUtil.ProbeHandler { + final LongArraySource hashSlots; + final ObjectArraySource sequentialBuilders; + + private RightProbeHandler() { + this.hashSlots = null; + this.sequentialBuilders = null; + } + + private RightProbeHandler(final LongArraySource hashSlots, + final ObjectArraySource sequentialBuilders) { + this.hashSlots = hashSlots; + this.sequentialBuilders = sequentialBuilders; + } + + @Override + public void doProbe(RowSequence chunkOk, Chunk[] sourceKeyChunks) { + probeRightSide(chunkOk, sourceKeyChunks, hashSlots, sequentialBuilders); + } + } + + @Override + public void probeRightInitial(RowSequence rightIndex, ColumnSource[] rightSources) { + if (rightIndex.isEmpty()) { + return; + } + try (final ProbeContext pc = makeProbeContext(rightSources, rightIndex.size())) { + probeTable(pc, rightIndex, false, rightSources, new RightProbeHandler()); + } + } + + private int accumulateIndices(RowSet rowSet, ColumnSource[] sources, LongArraySource slots, + ObjectArraySource sequentialBuilders, boolean usePrev) { + resetCookie(); + + if (rowSet.isEmpty()) { + return 0; + } + + try (final ProbeContext pc = makeProbeContext(sources, rowSet.size())) { + probeTable(pc, rowSet, usePrev, sources, new RightProbeHandler(slots, sequentialBuilders)); + } + + return nextCookie; + } + + @Override + public int buildAdditions(boolean isLeftSide, RowSet additions, ColumnSource[] sources, LongArraySource slots, + ObjectArraySource sequentialBuilders) { + + resetCookie(); + + if (additions.isEmpty()) { + return 0; + } + + try (final BuildContext bc = makeBuildContext(sources, additions.size())) { + if (isLeftSide) { + buildTable(false, bc, additions, sources, slots, new LeftBuildHandler(slots, sequentialBuilders)); + } else { + buildTable(false, bc, additions, sources, slots, new RightBuildHandler(slots, sequentialBuilders)); + } + return nextCookie; + } + } + + @Override + public int getTableSize() { + return tableSize; + } + + @Override + public int getOverflowSize() { + return 0; + } + + @Override + public WritableRowSet getAndClearLeftIndex(long slot) { + final RowSetBuilderSequential builder = (RowSetBuilderSequential) leftRowSetSource.getUnsafe(slot); + leftRowSetSource.set(slot, null); + if (builder == null) { + return null; + } + return builder.build(); + } + + @Override + public byte getState(long slot) { + final ImmutableByteArraySource source; + if ((slot & AlternatingColumnSource.ALTERNATE_SWITCH_MASK) == mainInsertMask) { + source = stateSource; + } else { + source = alternateStateSource; + } + // clear the mask bits + slot = slot & AlternatingColumnSource.ALTERNATE_INNER_MASK; + + return source.getUnsafe(slot); + } + + @Override + public SegmentedSortedArray getRightSsa(long slot) { + final ImmutableByteArraySource source; + final ImmutableObjectArraySource rowSetSource; + if ((slot & AlternatingColumnSource.ALTERNATE_SWITCH_MASK) == mainInsertMask) { + source = stateSource; + rowSetSource = rightRowSetSource; + } else { + source = alternateStateSource; + rowSetSource = alternateRightRowSetSource; + } + // clear the mask bits + slot = slot & AlternatingColumnSource.ALTERNATE_INNER_MASK; + + final byte entryType = source.getUnsafe(slot); + if ((entryType & ENTRY_RIGHT_MASK) == ENTRY_RIGHT_IS_SSA) { + return (SegmentedSortedArray) rowSetSource.getUnsafe(slot); + } + throw new IllegalStateException(); + } + + @Override + public SegmentedSortedArray getRightSsa(long slot, Function ssaFactory) { + final ImmutableByteArraySource source; + final ImmutableObjectArraySource rowSetSource; + if ((slot & AlternatingColumnSource.ALTERNATE_SWITCH_MASK) == mainInsertMask) { + source = stateSource; + rowSetSource = rightRowSetSource; + } else { + source = alternateStateSource; + rowSetSource = alternateRightRowSetSource; + } + // clear the mask bits + slot = slot & AlternatingColumnSource.ALTERNATE_INNER_MASK; + + final byte entryType = source.getUnsafe(slot); + switch (entryType & ENTRY_RIGHT_MASK) { + case ENTRY_RIGHT_IS_EMPTY: + return makeSsaFromEmpty(slot, ssaFactory, rowSetSource, source, + (byte) ((entryType & ENTRY_LEFT_MASK) | ENTRY_RIGHT_IS_SSA)); + case ENTRY_RIGHT_IS_INDEX: + return makeSsaFromIndex(slot, ssaFactory, rowSetSource, source, + (byte) ((entryType & ENTRY_LEFT_MASK) | ENTRY_RIGHT_IS_SSA)); + case ENTRY_RIGHT_IS_BUILDER: + return makeSsaFromBuilder(slot, ssaFactory, rowSetSource, source, + (byte) ((entryType & ENTRY_LEFT_MASK) | ENTRY_RIGHT_IS_SSA)); + case ENTRY_RIGHT_IS_SSA: + return (SegmentedSortedArray) rowSetSource.getUnsafe(slot); + } + throw new IllegalStateException(); + } + + @Override + public WritableRowSet getRightIndex(long slot) { + final ImmutableByteArraySource source; + final ImmutableObjectArraySource rowSetSource; + if ((slot & AlternatingColumnSource.ALTERNATE_SWITCH_MASK) == mainInsertMask) { + source = stateSource; + rowSetSource = rightRowSetSource; + } else { + source = alternateStateSource; + rowSetSource = alternateRightRowSetSource; + } + // clear the mask bits + slot = slot & AlternatingColumnSource.ALTERNATE_INNER_MASK; + + final byte entryType = source.getUnsafe(slot); + if ((entryType & ENTRY_RIGHT_MASK) == ENTRY_RIGHT_IS_INDEX) { + return (WritableRowSet) rowSetSource.getUnsafe(slot); + } else if ((entryType & ENTRY_RIGHT_MASK) == ENTRY_RIGHT_IS_BUILDER) { + final WritableRowSet rowSet = ((RowSetBuilderSequential) rowSetSource.getUnsafe(slot)).build(); + rowSetSource.set(slot, rowSet); + source.set(slot, (byte) ((entryType & ENTRY_LEFT_MASK) | ENTRY_RIGHT_IS_INDEX)); + return rowSet; + } + throw new IllegalStateException(); + } + + @Override + public WritableRowSet getLeftIndex(long slot) { + final ImmutableByteArraySource source; + final ImmutableObjectArraySource rowSetSource; + if ((slot & AlternatingColumnSource.ALTERNATE_SWITCH_MASK) == mainInsertMask) { + source = stateSource; + rowSetSource = leftRowSetSource; + } else { + source = alternateStateSource; + rowSetSource = alternateLeftRowSetSource; + } + // clear the mask bits + slot = slot & AlternatingColumnSource.ALTERNATE_INNER_MASK; + + final byte entryType = source.getUnsafe(slot); + if ((entryType & ENTRY_LEFT_MASK) == ENTRY_LEFT_IS_INDEX) { + return (WritableRowSet) rowSetSource.getUnsafe(slot); + } else if ((entryType & ENTRY_LEFT_MASK) == ENTRY_LEFT_IS_BUILDER) { + final WritableRowSet rowSet = ((RowSetBuilderSequential) rowSetSource.getUnsafe(slot)).build(); + rowSetSource.set(slot, rowSet); + source.set(slot, (byte) ((entryType & ENTRY_RIGHT_MASK) | ENTRY_LEFT_IS_INDEX)); + return rowSet; + } + throw new IllegalStateException(); + } + + @Override + public void setLeftIndex(long slot, RowSet rowSet) { + final ImmutableByteArraySource source; + final ImmutableObjectArraySource rowSetSource; + if ((slot & AlternatingColumnSource.ALTERNATE_SWITCH_MASK) == mainInsertMask) { + source = stateSource; + rowSetSource = leftRowSetSource; + } else { + source = alternateStateSource; + rowSetSource = alternateLeftRowSetSource; + } + // clear the mask bits + slot = slot & AlternatingColumnSource.ALTERNATE_INNER_MASK; + + final byte entryType = source.getUnsafe(slot); + if ((entryType & ENTRY_LEFT_MASK) == ENTRY_LEFT_IS_EMPTY) { + source.set(slot, (byte) ((entryType & ENTRY_RIGHT_MASK) | ENTRY_LEFT_IS_INDEX)); + rowSetSource.set(slot, rowSet); + return; + } + throw new IllegalStateException(); + } + + @Override + public void setRightIndex(long slot, RowSet rowSet) { + final ImmutableByteArraySource source; + final ImmutableObjectArraySource rowSetSource; + if ((slot & AlternatingColumnSource.ALTERNATE_SWITCH_MASK) == mainInsertMask) { + source = stateSource; + rowSetSource = rightRowSetSource; + } else { + source = alternateStateSource; + rowSetSource = alternateRightRowSetSource; + } + // clear the mask bits + slot = slot & AlternatingColumnSource.ALTERNATE_INNER_MASK; + + final byte entryType = source.getUnsafe(slot); + if ((entryType & ENTRY_RIGHT_MASK) == ENTRY_RIGHT_IS_EMPTY) { + source.set(slot, (byte) ((entryType & ENTRY_LEFT_MASK) | ENTRY_RIGHT_IS_INDEX)); + rowSetSource.set(slot, rowSet); + return; + } + throw new IllegalStateException(); + } + + @Override + public SegmentedSortedArray getLeftSsa(long slot) { + final ImmutableByteArraySource source; + final ImmutableObjectArraySource rowSetSource; + if ((slot & AlternatingColumnSource.ALTERNATE_SWITCH_MASK) == mainInsertMask) { + source = stateSource; + rowSetSource = leftRowSetSource; + } else { + source = alternateStateSource; + rowSetSource = alternateLeftRowSetSource; + } + // clear the mask bits + slot = slot & AlternatingColumnSource.ALTERNATE_INNER_MASK; + + final byte entryType = source.getUnsafe(slot); + if ((entryType & ENTRY_LEFT_MASK) == ENTRY_LEFT_IS_SSA) { + return (SegmentedSortedArray) rowSetSource.getUnsafe(slot); + } + throw new IllegalStateException(); + } + + @Override + public SegmentedSortedArray getLeftSsa(long slot, Function ssaFactory) { + final ImmutableByteArraySource source; + final ImmutableObjectArraySource rowSetSource; + if ((slot & AlternatingColumnSource.ALTERNATE_SWITCH_MASK) == mainInsertMask) { + source = stateSource; + rowSetSource = leftRowSetSource; + } else { + source = alternateStateSource; + rowSetSource = alternateLeftRowSetSource; + } + // clear the mask bits + slot = slot & AlternatingColumnSource.ALTERNATE_INNER_MASK; + + final byte entryType = source.getUnsafe(slot); + switch (entryType & ENTRY_LEFT_MASK) { + case ENTRY_LEFT_IS_EMPTY: + return makeSsaFromEmpty(slot, ssaFactory, rowSetSource, source, + (byte) ((entryType & ENTRY_RIGHT_MASK) | ENTRY_LEFT_IS_SSA)); + case ENTRY_LEFT_IS_BUILDER: + return makeSsaFromBuilder(slot, ssaFactory, rowSetSource, source, + (byte) ((entryType & ENTRY_RIGHT_MASK) | ENTRY_LEFT_IS_SSA)); + case ENTRY_LEFT_IS_INDEX: + return makeSsaFromIndex(slot, ssaFactory, rowSetSource, source, + (byte) ((entryType & ENTRY_RIGHT_MASK) | ENTRY_LEFT_IS_SSA)); + case ENTRY_LEFT_IS_SSA: + return (SegmentedSortedArray) rowSetSource.getUnsafe(slot); + } + throw new IllegalStateException(); + } + + @Override + public SegmentedSortedArray getLeftSsaOrIndex(long slot, MutableObject indexOutput) { + final ImmutableByteArraySource source; + final ImmutableObjectArraySource rowSetSource; + if ((slot & AlternatingColumnSource.ALTERNATE_SWITCH_MASK) == mainInsertMask) { + source = stateSource; + rowSetSource = leftRowSetSource; + } else { + source = alternateStateSource; + rowSetSource = alternateLeftRowSetSource; + } + // clear the mask bits + slot = slot & AlternatingColumnSource.ALTERNATE_INNER_MASK; + + final byte entryType = source.getUnsafe(slot); + final byte stateValueForIndex = (byte) ((entryType & ENTRY_RIGHT_MASK) | ENTRY_LEFT_IS_INDEX); + return getSsaOrIndex(indexOutput, slot, leftEntryAsRightType(entryType), rowSetSource, source, + stateValueForIndex); + } + + @Override + public SegmentedSortedArray getRightSsaOrIndex(long slot, MutableObject indexOutput) { + final ImmutableByteArraySource source; + final ImmutableObjectArraySource rowSetSource; + if ((slot & AlternatingColumnSource.ALTERNATE_SWITCH_MASK) == mainInsertMask) { + source = stateSource; + rowSetSource = rightRowSetSource; + } else { + source = alternateStateSource; + rowSetSource = alternateRightRowSetSource; + } + // clear the mask bits + slot = slot & AlternatingColumnSource.ALTERNATE_INNER_MASK; + + final byte entryType = source.getUnsafe(slot); + final byte stateValueForIndex = (byte) ((entryType & ENTRY_LEFT_MASK) | ENTRY_RIGHT_IS_INDEX); + return getSsaOrIndex(indexOutput, slot, getRightEntryType(entryType), rowSetSource, source, + stateValueForIndex); + } + + @Nullable + private static SegmentedSortedArray getSsaOrIndex(MutableObject indexOutput, long location, + byte entryType, ImmutableObjectArraySource sideSource, ImmutableByteArraySource stateSource, + byte stateValueForIndex) { + switch (entryType) { + case ENTRY_RIGHT_IS_SSA: + return (SegmentedSortedArray) sideSource.getUnsafe(location); + case ENTRY_RIGHT_IS_INDEX: + indexOutput.setValue((WritableRowSet) sideSource.getUnsafe(location)); + return null; + case ENTRY_RIGHT_IS_EMPTY: { + final WritableRowSet emptyRowSet = RowSetFactory.empty(); + sideSource.set(location, emptyRowSet); + stateSource.set(location, stateValueForIndex); + indexOutput.setValue(emptyRowSet); + return null; + } + case ENTRY_RIGHT_IS_BUILDER: { + final WritableRowSet rowSet = ((RowSetBuilderSequential) sideSource.getUnsafe(location)).build(); + sideSource.set(location, rowSet); + stateSource.set(location, stateValueForIndex); + indexOutput.setValue(rowSet); + return null; + } + default: + throw new IllegalStateException(); + } + } + + @Nullable + private SegmentedSortedArray makeSsaFromBuilder(long slot, Function ssaFactory, + ImmutableObjectArraySource ssaSource, ImmutableByteArraySource stateSource, byte newState) { + final RowSetBuilderSequential builder = (RowSetBuilderSequential) ssaSource.getUnsafe(slot); + final RowSet rowSet; + if (builder == null) { + rowSet = RowSetFactory.empty(); + } else { + rowSet = builder.build(); + } + return makeSsaFromIndex(slot, ssaFactory, ssaSource, stateSource, newState, rowSet); + } + + @Nullable + private SegmentedSortedArray makeSsaFromEmpty(long slot, Function ssaFactory, + ImmutableObjectArraySource ssaSource, ImmutableByteArraySource stateSource, byte newState) { + return makeSsaFromIndex(slot, ssaFactory, ssaSource, stateSource, newState, RowSetFactory.empty()); + } + + @Nullable + private SegmentedSortedArray makeSsaFromIndex(long slot, Function ssaFactory, + ImmutableObjectArraySource ssaSource, ImmutableByteArraySource stateSource, byte newState) { + return makeSsaFromIndex(slot, ssaFactory, ssaSource, stateSource, newState, (RowSet) ssaSource.getUnsafe(slot)); + } + + private SegmentedSortedArray makeSsaFromIndex(long slot, Function ssaFactory, + ImmutableObjectArraySource ssaSource, ImmutableByteArraySource stateSource, byte newState, + RowSet rowSet) { + stateSource.set(slot, newState); + final SegmentedSortedArray ssa = ssaFactory.apply(rowSet); + rowSet.close(); + ssaSource.set(slot, ssa); + return ssa; + } + + protected void newAlternate() { + alternateRightRowSetSource = rightRowSetSource; + rightRowSetSource = new ImmutableObjectArraySource<>(Object.class, null); + rightRowSetSource.ensureCapacity(tableSize); + + alternateLeftRowSetSource = leftRowSetSource; + leftRowSetSource = new ImmutableObjectArraySource<>(Object.class, null); + leftRowSetSource.ensureCapacity(tableSize); + + alternateStateSource = stateSource; + stateSource = new ImmutableByteArraySource(); + stateSource.ensureCapacity(tableSize); + + alternateCookieSource = mainCookieSource; + mainCookieSource = new ImmutableLongArraySource(); + mainCookieSource.ensureCapacity(tableSize); + + if (mainInsertMask == 0) { + mainInsertMask = (int) AlternatingColumnSource.ALTERNATE_SWITCH_MASK; + alternateInsertMask = 0; + } else { + mainInsertMask = 0; + alternateInsertMask = (int) AlternatingColumnSource.ALTERNATE_SWITCH_MASK; + } + } + + protected void clearAlternate() { + for (int ii = 0; ii < mainKeySources.length; ++ii) { + alternateKeySources[ii] = null; + } + + } + + /** + * @param fullRehash should we rehash the entire table (if false, we rehash incrementally) + * @param rehashCredits the number of entries this operation has rehashed (input/output) + * @param nextChunkSize the size of the chunk we are processing + * @return true if a front migration is required + */ + public boolean doRehash(boolean fullRehash, MutableInt rehashCredits, int nextChunkSize, + LongArraySource hashSlots) { + if (rehashPointer > 0) { + final int requiredRehash = nextChunkSize - rehashCredits.intValue(); + if (requiredRehash <= 0) { + return false; + } + + // before building, we need to do at least as much rehash work as we would do build work + rehashCredits.add(rehashInternalPartial(requiredRehash, hashSlots)); + if (rehashPointer == 0) { + clearAlternate(); + } + } + + int oldTableSize = tableSize; + while (rehashRequired(nextChunkSize)) { + tableSize *= 2; + + if (tableSize < 0 || tableSize > MAX_TABLE_SIZE) { + throw new UnsupportedOperationException("Hash table exceeds maximum size!"); + } + } + + if (oldTableSize == tableSize) { + return false; + } + + // we can't give the caller credit for rehashes with the old table, we need to begin migrating things again + if (rehashCredits.intValue() > 0) { + rehashCredits.setValue(0); + } + + if (fullRehash) { + // if we are doing a full rehash, we need to ditch the alternate + if (rehashPointer > 0) { + rehashInternalPartial((int) numEntries, hashSlots); + clearAlternate(); + } + + rehashInternalFull(oldTableSize); + + return false; + } + + Assert.eqZero(rehashPointer, "rehashPointer"); + + for (int ii = 0; ii < mainKeySources.length; ++ii) { + alternateKeySources[ii] = mainKeySources[ii]; + mainKeySources[ii] = InMemoryColumnSource.getImmutableMemoryColumnSource(tableSize, + alternateKeySources[ii].getType(), alternateKeySources[ii].getComponentType()); + mainKeySources[ii].ensureCapacity(tableSize); + } + alternateTableSize = oldTableSize; + if (numEntries > 0) { + rehashPointer = alternateTableSize; + } + + newAlternate(); + + return true; + } + + public boolean rehashRequired(int nextChunkSize) { + return (numEntries + nextChunkSize) > (tableSize * maximumLoadFactor); + } + + protected int hashToTableLocation(int hash) { + return hash & (tableSize - 1); + } + + protected int hashToTableLocationAlternate(int hash) { + return hash & (alternateTableSize - 1); + } + + abstract protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + final LongArraySource hashSlots, final ObjectArraySource sequentialBuilders); + + abstract protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + final LongArraySource hashSlots, final ObjectArraySource sequentialBuilders); + + abstract protected void probeRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + final LongArraySource hashSlots, final ObjectArraySource sequentialBuilders); + + abstract protected int rehashInternalPartial(int entriesToRehash, LongArraySource hashSlots); + + abstract protected void migrateFront(LongArraySource hashSlots); + + abstract protected void rehashInternalFull(final int oldSize); +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/RightIncrementalHashedAsOfJoinStateManager.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/RightIncrementalHashedAsOfJoinStateManager.java new file mode 100644 index 00000000000..928259f6c02 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/RightIncrementalHashedAsOfJoinStateManager.java @@ -0,0 +1,91 @@ +package io.deephaven.engine.table.impl.asofjoin; + +import io.deephaven.engine.rowset.*; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.JoinControl; +import io.deephaven.engine.table.impl.QueryTable; +import io.deephaven.engine.table.impl.RightIncrementalAsOfJoinStateManager; +import io.deephaven.engine.table.impl.StaticAsOfJoinStateManager; +import io.deephaven.engine.table.impl.sources.*; +import io.deephaven.engine.table.impl.ssa.SegmentedSortedArray; +import io.deephaven.engine.table.impl.util.ContiguousWritableRowRedirection; +import io.deephaven.engine.table.impl.util.LongColumnSourceWritableRowRedirection; +import io.deephaven.engine.table.impl.util.WritableRowRedirection; +import io.deephaven.engine.table.impl.util.WritableRowRedirectionLockFree; +import io.deephaven.util.QueryConstants; +import org.apache.commons.lang3.mutable.MutableObject; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; +import java.util.function.LongUnaryOperator; + +public abstract class RightIncrementalHashedAsOfJoinStateManager extends RightIncrementalAsOfJoinStateManager { + protected RightIncrementalHashedAsOfJoinStateManager(ColumnSource[] keySourcesForErrorMessages) { + super(keySourcesForErrorMessages); + } + + public static final byte ENTRY_RIGHT_MASK = 0x3; + public static final byte ENTRY_RIGHT_IS_EMPTY = 0x0; + public static final byte ENTRY_RIGHT_IS_BUILDER = 0x1; + public static final byte ENTRY_RIGHT_IS_SSA = 0x2; + public static final byte ENTRY_RIGHT_IS_INDEX = 0x3; + + public static final byte ENTRY_LEFT_MASK = 0x30; + public static final byte ENTRY_LEFT_IS_EMPTY = 0x00; + public static final byte ENTRY_LEFT_IS_BUILDER = 0x10; + public static final byte ENTRY_LEFT_IS_SSA = 0x20; + public static final byte ENTRY_LEFT_IS_INDEX = 0x30; + + public static final byte ENTRY_INITIAL_STATE_LEFT = ENTRY_LEFT_IS_BUILDER|ENTRY_RIGHT_IS_EMPTY; + public static final byte ENTRY_INITIAL_STATE_RIGHT = ENTRY_LEFT_IS_EMPTY|ENTRY_RIGHT_IS_BUILDER; + + protected void addToSequentialBuilder(long slot, @NotNull ObjectArraySource sequentialBuilders, long indexKey) { + RowSetBuilderSequential builder = sequentialBuilders.getUnsafe(slot); + if (builder == null) { + builder = RowSetFactory.builderSequential(); + sequentialBuilders.set(slot, builder); + } + builder.appendKey(indexKey); + } + + protected byte leftEntryAsRightType(byte entryType) { + return (byte)((entryType & ENTRY_LEFT_MASK) >> 4); + } + + protected byte getRightEntryType(byte entryType) { + return (byte)(entryType & ENTRY_RIGHT_MASK); + } + + public abstract int buildFromLeftSide(RowSequence leftRowSet, ColumnSource[] leftSources, @NotNull final LongArraySource addedSlots); + public abstract int buildFromRightSide(RowSequence rightRowSet, ColumnSource[] rightSources, @NotNull final LongArraySource addedSlots, int usedSlots); + + public abstract void probeRightInitial(RowSequence rightIndex, ColumnSource[] rightSources); + public abstract int probeAdditions(RowSet restampAdditions, ColumnSource[] sources, LongArraySource slots, ObjectArraySource sequentialBuilders); + public abstract int buildAdditions(boolean isLeftSide, RowSet additions, ColumnSource[] sources, LongArraySource slots, ObjectArraySource sequentialBuilders); + + public abstract SegmentedSortedArray getRightSsa(long slot); + public abstract SegmentedSortedArray getRightSsa(long slot, Function ssaFactory); + public abstract SegmentedSortedArray getLeftSsa(long slot); + public abstract SegmentedSortedArray getLeftSsa(long slot, Function ssaFactory); + + public abstract SegmentedSortedArray getLeftSsaOrIndex(long slot, MutableObject indexOutput); + public abstract SegmentedSortedArray getRightSsaOrIndex(long slot, MutableObject indexOutput); + public abstract void setRightIndex(long slot, RowSet rowSet); + public abstract void setLeftIndex(long slot, RowSet rowSet); + public abstract WritableRowSet getLeftIndex(long slot); + public abstract WritableRowSet getRightIndex(long slot); + + public abstract WritableRowSet getAndClearLeftIndex(long slot); + + public abstract int markForRemoval(RowSet restampRemovals, ColumnSource[] sources, LongArraySource slots, ObjectArraySource sequentialBuilders); + + public abstract int gatherShiftIndex(RowSet restampAdditions, ColumnSource[] sources, LongArraySource slots, ObjectArraySource sequentialBuilders); + + public abstract int gatherModifications(RowSet restampAdditions, ColumnSource[] sources, LongArraySource slots, ObjectArraySource sequentialBuilders); + + public abstract byte getState(long slot); + + public abstract int getTableSize(); + public abstract int getOverflowSize(); +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/StaticAsOfJoinStateManagerTypedBase.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/StaticAsOfJoinStateManagerTypedBase.java new file mode 100644 index 00000000000..44833679050 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/StaticAsOfJoinStateManagerTypedBase.java @@ -0,0 +1,402 @@ +package io.deephaven.engine.table.impl.asofjoin; + +import io.deephaven.base.verify.Require; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.ChunkType; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.engine.rowset.*; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.WritableColumnSource; +import io.deephaven.engine.table.impl.sources.InMemoryColumnSource; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.ObjectArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableObjectArraySource; +import io.deephaven.engine.table.impl.util.TypedHasherUtil; +import io.deephaven.engine.table.impl.util.TypedHasherUtil.BuildOrProbeContext.BuildContext; +import io.deephaven.engine.table.impl.util.TypedHasherUtil.BuildOrProbeContext.ProbeContext; +import org.apache.commons.lang3.mutable.MutableInt; +import org.jetbrains.annotations.NotNull; + +import static io.deephaven.engine.table.impl.util.TypedHasherUtil.getKeyChunks; +import static io.deephaven.engine.table.impl.util.TypedHasherUtil.getPrevKeyChunks; + +public abstract class StaticAsOfJoinStateManagerTypedBase extends StaticHashedAsOfJoinStateManager { + public static final int CHUNK_SIZE = 4096; + private static final long MAX_TABLE_SIZE = 1 << 30; // maximum array size + public static final Object EMPTY_RIGHT_STATE = null; + + // the number of slots in our table + protected int tableSize; + + protected long numEntries = 0; + + // the table will be rehashed to a load factor of targetLoadFactor if our loadFactor exceeds maximumLoadFactor + // or if it falls below minimum load factor we will instead contract the table + private final double maximumLoadFactor; + + // the keys for our hash entries + protected final ChunkType[] chunkTypes; + protected final WritableColumnSource[] mainKeySources; + + protected final ImmutableObjectArraySource leftRowSetSource; + + /** + * For the ticking case we need to reuse our right rowsets for more than one update. We convert the + * SequentialBuilders into actual RowSet objects. Before the conversion (which must be during the build phase) we + * put the sequential builders into rightRowSetSource. After the conversion, the sources store actual rowsets. + */ + private boolean rightBuildersConverted = false; + + protected final ImmutableObjectArraySource rightRowSetSource; + + protected StaticAsOfJoinStateManagerTypedBase(ColumnSource[] tableKeySources, + ColumnSource[] keySourcesForErrorMessages, int tableSize, double maximumLoadFactor) { + // region super + super(keySourcesForErrorMessages); + // endregion super + + this.tableSize = tableSize; + Require.leq(tableSize, "tableSize", MAX_TABLE_SIZE); + Require.gtZero(tableSize, "tableSize"); + Require.eq(Integer.bitCount(tableSize), "Integer.bitCount(tableSize)", 1); + Require.inRange(maximumLoadFactor, 0.0, 0.95, "maximumLoadFactor"); + + // region constructor + mainKeySources = new WritableColumnSource[tableKeySources.length]; + chunkTypes = new ChunkType[tableKeySources.length]; + leftRowSetSource = new ImmutableObjectArraySource<>(RowSetBuilderSequential.class, null); + rightRowSetSource = new ImmutableObjectArraySource<>(Object.class, null); + // endregion constructor + + for (int ii = 0; ii < tableKeySources.length; ++ii) { + chunkTypes[ii] = keySourcesForErrorMessages[ii].getChunkType(); + mainKeySources[ii] = InMemoryColumnSource.getImmutableMemoryColumnSource(tableSize, + tableKeySources[ii].getType(), tableKeySources[ii].getComponentType()); + } + + this.maximumLoadFactor = maximumLoadFactor; + + ensureCapacity(tableSize); + } + + private void ensureCapacity(int tableSize) { + for (WritableColumnSource mainKeySource : mainKeySources) { + mainKeySource.ensureCapacity(tableSize); + } + // region ensureCapacity + leftRowSetSource.ensureCapacity(tableSize); + rightRowSetSource.ensureCapacity(tableSize); + // endregion ensureCapacity + } + + BuildContext makeBuildContext(ColumnSource[] buildSources, long maxSize) { + return new BuildContext(buildSources, (int) Math.min(CHUNK_SIZE, maxSize)); + } + + ProbeContext makeProbeContext(ColumnSource[] buildSources, long maxSize) { + return new ProbeContext(buildSources, (int) Math.min(CHUNK_SIZE, maxSize)); + } + + static boolean addIndex(ImmutableObjectArraySource source, long location, long keyToAdd) { + boolean addedSlot = false; + RowSetBuilderSequential builder = source.getUnsafe(location); + if (builder == null) { + source.set(location, builder = RowSetFactory.builderSequential()); + addedSlot = true; + } + builder.appendKey(keyToAdd); + return addedSlot; + } + + /** + * Returns true if this is the first left row key added to this slot. + */ + protected boolean addLeftIndex(long tableLocation, long keyToAdd) { + return addIndex(leftRowSetSource, tableLocation, keyToAdd); + } + + protected void addRightIndex(long tableLocation, long keyToAdd) { + // noinspection unchecked + addIndex((ImmutableObjectArraySource) rightRowSetSource, tableLocation, keyToAdd); + } + + protected void buildTable( + final BuildContext bc, + final RowSequence buildRows, + final ColumnSource[] buildSources, + final TypedHasherUtil.BuildHandler buildHandler) { + try (final RowSequence.Iterator rsIt = buildRows.getRowSequenceIterator()) { + // noinspection unchecked + final Chunk[] sourceKeyChunks = new Chunk[buildSources.length]; + + while (rsIt.hasMore()) { + final RowSequence chunkOk = rsIt.getNextRowSequenceWithLength(bc.chunkSize); + + doRehash(chunkOk.intSize()); + + getKeyChunks(buildSources, bc.getContexts, sourceKeyChunks, chunkOk); + + buildHandler.doBuild(chunkOk, sourceKeyChunks); + + bc.resetSharedContexts(); + } + } + } + + private class LeftBuildHandler implements TypedHasherUtil.BuildHandler { + @Override + public void doBuild(RowSequence chunkOk, Chunk[] sourceKeyChunks) { + buildFromLeftSide(chunkOk, sourceKeyChunks); + } + } + + private class RightBuildHandler implements TypedHasherUtil.BuildHandler { + @Override + public void doBuild(RowSequence chunkOk, Chunk[] sourceKeyChunks) { + buildFromRightSide(chunkOk, sourceKeyChunks); + } + } + + private int fillSlotsFromHashTable(@NotNull final LongArraySource slotArray) { + slotArray.ensureCapacity(tableSize); + long slotCount = 0; + for (long slotIdx = 0; slotIdx < tableSize; slotIdx++) { + if (rightRowSetSource.get(slotIdx) != EMPTY_RIGHT_STATE) { + slotArray.set(slotCount++, slotIdx); + } + } + return (int) slotCount; + } + + @Override + public int buildFromLeftSide(RowSequence leftRowSet, ColumnSource[] leftSources, + @NotNull final LongArraySource addedSlots) { + if (leftRowSet.isEmpty()) { + return 0; + } + try (final BuildContext bc = makeBuildContext(leftSources, leftRowSet.size())) { + buildTable(bc, leftRowSet, leftSources, new LeftBuildHandler()); + return fillSlotsFromHashTable(addedSlots); + } + } + + @Override + public int buildFromRightSide(RowSequence rightRowSet, ColumnSource[] rightSources, + @NotNull final LongArraySource addedSlots) { + if (rightRowSet.isEmpty()) { + return 0; + } + try (final BuildContext bc = makeBuildContext(rightSources, rightRowSet.size())) { + buildTable(bc, rightRowSet, rightSources, new RightBuildHandler()); + return fillSlotsFromHashTable(addedSlots); + } + } + + protected void probeTable( + final ProbeContext pc, + final RowSequence probeRows, + final boolean usePrev, + final ColumnSource[] probeSources, + final TypedHasherUtil.ProbeHandler handler) { + try (final RowSequence.Iterator rsIt = probeRows.getRowSequenceIterator()) { + // noinspection unchecked + final Chunk[] sourceKeyChunks = new Chunk[probeSources.length]; + + while (rsIt.hasMore()) { + final RowSequence chunkOk = rsIt.getNextRowSequenceWithLength(pc.chunkSize); + + if (usePrev) { + getPrevKeyChunks(probeSources, pc.getContexts, sourceKeyChunks, chunkOk); + } else { + getKeyChunks(probeSources, pc.getContexts, sourceKeyChunks, chunkOk); + } + + handler.doProbe(chunkOk, sourceKeyChunks); + + pc.resetSharedContexts(); + } + } + } + + private class LeftProbeHandler implements TypedHasherUtil.ProbeHandler { + final LongArraySource hashSlots; + final MutableInt hashOffset; + final RowSetBuilderRandom foundBuilder; + + private LeftProbeHandler() { + this.hashSlots = null; + this.hashOffset = null; + this.foundBuilder = null; + } + + private LeftProbeHandler(final LongArraySource hashSlots, final MutableInt hashOffset, + RowSetBuilderRandom foundBuilder) { + this.hashSlots = hashSlots; + this.hashOffset = hashOffset; + this.foundBuilder = foundBuilder; + } + + @Override + public void doProbe(RowSequence chunkOk, Chunk[] sourceKeyChunks) { + decorateLeftSide(chunkOk, sourceKeyChunks, hashSlots, hashOffset, foundBuilder); + } + } + + private class RightProbeHandler implements TypedHasherUtil.ProbeHandler { + @Override + public void doProbe(RowSequence chunkOk, Chunk[] sourceKeyChunks) { + decorateWithRightSide(chunkOk, sourceKeyChunks); + } + } + + @Override + public void probeLeft(RowSequence leftRowSet, ColumnSource[] leftSources) { + if (leftRowSet.isEmpty()) { + return; + } + try (final ProbeContext pc = makeProbeContext(leftSources, leftRowSet.size())) { + probeTable(pc, leftRowSet, false, leftSources, new LeftProbeHandler()); + } + } + + @Override + public int probeLeft(RowSequence leftRowSet, ColumnSource[] leftSources, @NotNull final LongArraySource slots, + RowSetBuilderRandom foundBuilder) { + if (leftRowSet.isEmpty()) { + return 0; + } + try (final ProbeContext pc = makeProbeContext(leftSources, leftRowSet.size())) { + final MutableInt slotCount = new MutableInt(); + probeTable(pc, leftRowSet, false, leftSources, new LeftProbeHandler(slots, slotCount, foundBuilder)); + return slotCount.intValue(); + } + } + + @Override + public void probeRight(RowSequence rightRowSet, ColumnSource[] rightSources) { + if (rightRowSet.isEmpty()) { + return; + } + try (final ProbeContext pc = makeProbeContext(rightSources, rightRowSet.size())) { + probeTable(pc, rightRowSet, false, rightSources, new RightProbeHandler()); + } + } + + @Override + public int getTableSize() { + return tableSize; + } + + @Override + public int getOverflowSize() { + return 0; + } + + /** + * When we get the left RowSet out of our source (after a build or probe); we do it by pulling a sequential builder + * and then calling build(). We also null out the value in the column source, thus freeing the builder's memory. + * + * This also results in clearing out the left hand side of the table between each probe phase for the left + * refreshing case. + * + * @param slot the slot in the table + * @return the RowSet for this slot + */ + @Override + public RowSet getLeftIndex(long slot) { + RowSetBuilderSequential builder = (RowSetBuilderSequential) leftRowSetSource.getAndSetUnsafe(slot, null); + if (builder == null) { + return null; + } + return builder.build(); + } + + @Override + public RowSet getRightIndex(long slot) { + if (rightBuildersConverted) { + return (RowSet) rightRowSetSource.getUnsafe(slot); + } + throw new IllegalStateException( + "getRightIndex() may not be called before convertRightBuildersToIndex() or convertRightGrouping()"); + } + + @Override + public void convertRightBuildersToIndex(LongArraySource slots, int slotCount) { + for (int slotIndex = 0; slotIndex < slotCount; ++slotIndex) { + final long slot = slots.getLong(slotIndex); + // this might be empty, if so then set null + final RowSetBuilderSequential sequentialBuilder = + (RowSetBuilderSequential) rightRowSetSource.getUnsafe(slot); + if (sequentialBuilder != null) { + WritableRowSet rs = sequentialBuilder.build(); + if (rs.isEmpty()) { + rightRowSetSource.set(slot, EMPTY_RIGHT_STATE); + rs.close(); + } else { + rightRowSetSource.set(slot, rs); + } + } + } + rightBuildersConverted = true; + } + + @Override + public void convertRightGrouping(LongArraySource slots, int slotCount, ObjectArraySource rowSetSource) { + for (int slotIndex = 0; slotIndex < slotCount; ++slotIndex) { + final long slot = slots.getLong(slotIndex); + + final RowSetBuilderSequential sequentialBuilder = + (RowSetBuilderSequential) rightRowSetSource.getUnsafe(slot); + if (sequentialBuilder != null) { + WritableRowSet rs = sequentialBuilder.build(); + if (rs.isEmpty()) { + rightRowSetSource.set(slot, EMPTY_RIGHT_STATE); + rs.close(); + } else { + rightRowSetSource.set(slot, getGroupedIndex(rowSetSource, sequentialBuilder)); + } + } + } + rightBuildersConverted = true; + } + + private RowSet getGroupedIndex(ObjectArraySource rowSetSource, RowSetBuilderSequential sequentialBuilder) { + final RowSet groupedRowSet = sequentialBuilder.build(); + if (groupedRowSet.size() != 1) { + throw new IllegalStateException("Grouped rowSet should have exactly one value: " + groupedRowSet); + } + return rowSetSource.getUnsafe(groupedRowSet.get(0)); + } + + abstract protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks); + + abstract protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks); + + abstract protected void decorateLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, MutableInt hashSlotOffset, RowSetBuilderRandom foundBuilder); + + abstract protected void decorateWithRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks); + + public void doRehash(final int nextChunkSize) { + final int oldSize = tableSize; + while (rehashRequired(nextChunkSize)) { + tableSize *= 2; + if (tableSize < 0 || tableSize > MAX_TABLE_SIZE) { + throw new UnsupportedOperationException("Hash table exceeds maximum size!"); + } + } + if (tableSize > oldSize) { + rehashInternalFull(oldSize); + } + } + + public boolean rehashRequired(int nextChunkSize) { + return (numEntries + nextChunkSize) > (tableSize * maximumLoadFactor); + } + + abstract protected void rehashInternalFull(final int oldSize); + + protected int hashToTableLocation(int hash) { + return hash & (tableSize - 1); + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/StaticHashedAsOfJoinStateManager.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/StaticHashedAsOfJoinStateManager.java new file mode 100644 index 00000000000..fb6e8e86a33 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/StaticHashedAsOfJoinStateManager.java @@ -0,0 +1,31 @@ +package io.deephaven.engine.table.impl.asofjoin; + +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.RowSet; +import io.deephaven.engine.rowset.RowSetBuilderRandom; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.StaticAsOfJoinStateManager; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.ObjectArraySource; +import org.jetbrains.annotations.NotNull; + +public abstract class StaticHashedAsOfJoinStateManager extends StaticAsOfJoinStateManager { + protected StaticHashedAsOfJoinStateManager(ColumnSource[] keySourcesForErrorMessages) { + super(keySourcesForErrorMessages); + } + + public abstract int buildFromLeftSide(RowSequence leftRowSet, ColumnSource[] leftSources, @NotNull final LongArraySource addedSlots); + public abstract int buildFromRightSide(RowSequence rightRowSet, ColumnSource[] rightSources, @NotNull final LongArraySource addedSlots); + + public abstract void probeLeft(RowSequence leftRowSet, ColumnSource[] leftSources); + public abstract int probeLeft(RowSequence leftRowSet, ColumnSource[] leftSources, LongArraySource slots, RowSetBuilderRandom foundBuilder); + public abstract void probeRight(RowSequence rightRowSet, ColumnSource[] rightSources); + + public abstract int getTableSize(); + public abstract int getOverflowSize(); + public abstract RowSet getLeftIndex(long slot); + public abstract RowSet getRightIndex(long slot); + + public abstract void convertRightBuildersToIndex(LongArraySource slots, int slotCount); + public abstract void convertRightGrouping(LongArraySource slots, int slotCount, ObjectArraySource rowSetSource); +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/TypedAsOfJoinFactory.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/TypedAsOfJoinFactory.java new file mode 100644 index 00000000000..5986f178e8d --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/TypedAsOfJoinFactory.java @@ -0,0 +1,181 @@ +package io.deephaven.engine.table.impl.asofjoin; + +import com.squareup.javapoet.CodeBlock; +import io.deephaven.base.verify.Assert; +import io.deephaven.engine.rowset.RowSetFactory; +import io.deephaven.engine.table.impl.by.typed.HasherConfig; +import io.deephaven.util.QueryConstants; + +public class TypedAsOfJoinFactory { + public static void staticBuildLeftFound(HasherConfig hasherConfig, boolean alternate, + CodeBlock.Builder builder) { + builder.addStatement("addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition))"); + } + + public static void staticBuildLeftInsert(HasherConfig hasherConfig, CodeBlock.Builder builder) { + builder.addStatement("addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition))"); + builder.addStatement("rightRowSetSource.set(tableLocation, $T.builderSequential())", RowSetFactory.class); + } + + public static void staticBuildRightFound(HasherConfig hasherConfig, boolean alternate, + CodeBlock.Builder builder) { + builder.addStatement("addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition))"); + } + + public static void staticBuildRightInsert(HasherConfig hasherConfig, CodeBlock.Builder builder) { + builder.addStatement("addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition))"); + } + + public static void staticProbeDecorateLeftFound(HasherConfig hasherConfig, boolean alternate, + CodeBlock.Builder builder) { + builder.addStatement("final long indexKey = rowKeyChunk.get(chunkPosition)"); + builder.beginControlFlow("if (addLeftIndex(tableLocation, indexKey) && hashSlots != null)"); + builder.addStatement("hashSlots.set(hashSlotOffset.getAndIncrement(), (long)tableLocation)"); + builder.addStatement("foundBuilder.addKey(indexKey)"); + builder.endControlFlow(); + } + + public static void staticProbeDecorateRightFound(HasherConfig hasherConfig, boolean alternate, + CodeBlock.Builder builder) { + builder.addStatement("addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition))"); + } + + public static void staticRehashSetup(CodeBlock.Builder builder) { + builder.addStatement("final Object [] oldLeftState = leftRowSetSource.getArray()"); + builder.addStatement("final Object [] destLeftState = new Object[tableSize]"); + builder.addStatement("leftRowSetSource.setArray(destLeftState)"); + } + + public static void staticMoveMainFull(CodeBlock.Builder builder) { + builder.addStatement("destLeftState[destinationTableLocation] = oldLeftState[sourceBucket]"); + } + + public static void rightIncrementalRehashSetup(CodeBlock.Builder builder) { + builder.addStatement("final Object [] oldLeftSource = leftRowSetSource.getArray()"); + builder.addStatement("final Object [] destLeftSource = new Object[tableSize]"); + builder.addStatement("leftRowSetSource.setArray(destLeftSource)"); + + builder.addStatement("final Object [] oldRightSource = rightRowSetSource.getArray()"); + builder.addStatement("final Object [] destRightSource = new Object[tableSize]"); + builder.addStatement("rightRowSetSource.setArray(destRightSource)"); + + builder.addStatement("final long [] oldModifiedCookie = mainCookieSource.getArray()"); + builder.addStatement("final long [] destModifiedCookie = new long[tableSize]"); + builder.addStatement("Arrays.fill(destModifiedCookie, $T.NULL_LONG)", QueryConstants.class); + builder.addStatement("mainCookieSource.setArray(destModifiedCookie)"); + } + + public static void rightIncrementalMoveMainFull(CodeBlock.Builder builder) { + builder.addStatement("destLeftSource[destinationTableLocation] = oldLeftSource[sourceBucket]"); + builder.addStatement("destRightSource[destinationTableLocation] = oldRightSource[sourceBucket]"); + builder.addStatement("destModifiedCookie[destinationTableLocation] = oldModifiedCookie[sourceBucket]"); + } + + public static void rightIncrementalMoveMainAlternate(CodeBlock.Builder builder) { + builder.addStatement( + "leftRowSetSource.set(destinationTableLocation, alternateLeftRowSetSource.getUnsafe(locationToMigrate))"); + builder.addStatement("alternateLeftRowSetSource.set(locationToMigrate, null)"); + builder.addStatement( + "rightRowSetSource.set(destinationTableLocation, alternateRightRowSetSource.getUnsafe(locationToMigrate))"); + builder.addStatement("alternateRightRowSetSource.set(locationToMigrate, null)"); + + builder.addStatement("final long cookie = alternateCookieSource.getUnsafe(locationToMigrate)"); + builder.addStatement("migrateCookie(cookie, destinationTableLocation, hashSlots)"); + } + + public static void rightIncrementalBuildLeftFound(HasherConfig hasherConfig, boolean alternate, + CodeBlock.Builder builder) { + if (!alternate) { + builder.addStatement("final long cookie = getCookieMain(tableLocation)"); + builder.addStatement("assert hashSlots != null"); + builder.addStatement("hashSlots.set(cookie, (long)tableLocation | mainInsertMask)"); + + builder.beginControlFlow("if (sequentialBuilders != null)"); + builder.addStatement("addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition))"); + builder.nextControlFlow("else"); + builder.addStatement("addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState)"); + builder.endControlFlow(); + } else { + builder.addStatement("final long cookie = getCookieAlternate(alternateTableLocation)"); + builder.addStatement("hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask)"); + + builder.beginControlFlow("if (sequentialBuilders != null)"); + builder.addStatement("addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition))"); + builder.nextControlFlow("else"); + builder.addStatement( + "addAlternateLeftIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState)"); + builder.endControlFlow(); + } + } + + public static void rightIncrementalBuildLeftInsert(HasherConfig hasherConfig, CodeBlock.Builder builder) { + builder.addStatement("final long cookie = makeCookieMain(tableLocation)"); + builder.addStatement("hashSlots.set(cookie, (long)tableLocation | mainInsertMask)"); + + builder.beginControlFlow("if (sequentialBuilders != null)"); + builder.addStatement("addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition))"); + builder.addStatement("stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY))"); + builder.nextControlFlow("else"); + builder.addStatement("addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0)"); + builder.endControlFlow(); + } + + public static void rightIncrementalRightFound(HasherConfig hasherConfig, boolean alternate, + CodeBlock.Builder builder) { + if (!alternate) { + builder.addStatement("final long cookie = getCookieMain(tableLocation)"); + builder.addStatement("hashSlots.set(cookie, (long)tableLocation | mainInsertMask)"); + + builder.beginControlFlow("if (sequentialBuilders != null)"); + builder.addStatement("addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition))"); + builder.nextControlFlow("else"); + builder.addStatement("addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState)"); + builder.endControlFlow(); + } else { + builder.addStatement("final long cookie = getCookieAlternate(alternateTableLocation)"); + builder.addStatement("hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask)"); + + builder.beginControlFlow("if (sequentialBuilders != null)"); + builder.addStatement("addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition))"); + builder.nextControlFlow("else"); + builder.addStatement( + "addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState)"); + builder.endControlFlow(); + } + } + + public static void rightIncrementalRightInsert(HasherConfig hasherConfig, CodeBlock.Builder builder) { + builder.addStatement("final long cookie = makeCookieMain(tableLocation)"); + builder.addStatement("hashSlots.set(cookie, (long)tableLocation | mainInsertMask)"); + + builder.beginControlFlow("if (sequentialBuilders != null)"); + builder.addStatement("addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition))"); + builder.addStatement("stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY))"); + builder.nextControlFlow("else"); + builder.addStatement("addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0)"); + builder.endControlFlow(); + } + + public static void rightIncrementalProbeDecorateRightFound(HasherConfig hasherConfig, boolean alternate, + CodeBlock.Builder builder) { + if (!alternate) { + builder.beginControlFlow("if (sequentialBuilders != null)"); + builder.addStatement("final long cookie = getCookieMain(tableLocation)"); + builder.addStatement("hashSlots.set(cookie, (long)tableLocation | mainInsertMask)"); + builder.addStatement("addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition))"); + builder.nextControlFlow("else"); + builder.addStatement("addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState)"); + builder.endControlFlow(); + } else { + builder.beginControlFlow("if (sequentialBuilders != null)"); + builder.addStatement("final long cookie = getCookieAlternate(alternateTableLocation)"); + builder.addStatement("hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask)"); + builder.addStatement("addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition))"); + builder.nextControlFlow("else"); + builder.addStatement( + "addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState)"); + builder.endControlFlow(); + + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherByte.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherByte.java new file mode 100644 index 00000000000..ae86402b39a --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherByte.java @@ -0,0 +1,319 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.rightincopen.gen; + +import static io.deephaven.util.compare.ByteComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.ByteChunk; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.ByteChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.ObjectArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableByteArraySource; +import io.deephaven.util.QueryConstants; +import java.lang.Override; +import java.util.Arrays; + +final class RightIncrementalAsOfJoinHasherByte extends RightIncrementalAsOfJoinStateManagerTypedBase { + private ImmutableByteArraySource mainKeySource0; + + private ImmutableByteArraySource alternateKeySource0; + + public RightIncrementalAsOfJoinHasherByte(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableByteArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + private int alternateNextTableLocation(int tableLocation) { + return (tableLocation + 1) & (alternateTableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final ByteChunk keyChunk0 = sourceKeyChunks[0].asByteChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final byte k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateLeftIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + assert hashSlots != null; + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final ByteChunk keyChunk0 = sourceKeyChunks[0].asByteChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final byte k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void probeRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final ByteChunk keyChunk0 = sourceKeyChunks[0].asByteChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final byte k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + boolean found = false; + int tableLocation = firstTableLocation; + byte rowState; + while ((rowState = stateSource.getUnsafe(tableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + found = true; + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + if (!found) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + if (firstAlternateTableLocation < rehashPointer) { + int alternateTableLocation = firstAlternateTableLocation; + while ((rowState = alternateStateSource.getUnsafe(alternateTableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + } + } + } + + private static int hash(byte k0) { + int hash = ByteChunkHasher.hashInitialSingle(k0); + return hash; + } + + private boolean migrateOneLocation(int locationToMigrate, LongArraySource hashSlots) { + final byte currentStateValue = alternateStateSource.getUnsafe(locationToMigrate); + if (currentStateValue == ENTRY_EMPTY_STATE) { + return false; + } + final byte k0 = alternateKeySource0.getUnsafe(locationToMigrate); + final int hash = hash(k0); + int destinationTableLocation = hashToTableLocation(hash); + while (stateSource.getUnsafe(destinationTableLocation) != ENTRY_EMPTY_STATE) { + destinationTableLocation = nextTableLocation(destinationTableLocation); + } + mainKeySource0.set(destinationTableLocation, k0); + stateSource.set(destinationTableLocation, currentStateValue); + leftRowSetSource.set(destinationTableLocation, alternateLeftRowSetSource.getUnsafe(locationToMigrate)); + alternateLeftRowSetSource.set(locationToMigrate, null); + rightRowSetSource.set(destinationTableLocation, alternateRightRowSetSource.getUnsafe(locationToMigrate)); + alternateRightRowSetSource.set(locationToMigrate, null); + final long cookie = alternateCookieSource.getUnsafe(locationToMigrate); + migrateCookie(cookie, destinationTableLocation, hashSlots); + alternateStateSource.set(locationToMigrate, ENTRY_EMPTY_STATE); + return true; + } + + @Override + protected int rehashInternalPartial(int entriesToRehash, LongArraySource hashSlots) { + int rehashedEntries = 0; + while (rehashPointer > 0 && rehashedEntries < entriesToRehash) { + if (migrateOneLocation(--rehashPointer, hashSlots)) { + rehashedEntries++; + } + } + return rehashedEntries; + } + + @Override + protected void newAlternate() { + super.newAlternate(); + this.mainKeySource0 = (ImmutableByteArraySource)super.mainKeySources[0]; + this.alternateKeySource0 = (ImmutableByteArraySource)super.alternateKeySources[0]; + } + + @Override + protected void clearAlternate() { + super.clearAlternate(); + this.alternateKeySource0 = null; + } + + @Override + protected void migrateFront(LongArraySource hashSlots) { + int location = 0; + while (migrateOneLocation(location++, hashSlots)); + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final byte[] destKeyArray0 = new byte[tableSize]; + final byte[] destState = new byte[tableSize]; + Arrays.fill(destState, ENTRY_EMPTY_STATE); + final byte [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final byte [] originalStateArray = stateSource.getArray(); + stateSource.setArray(destState); + final Object [] oldLeftSource = leftRowSetSource.getArray(); + final Object [] destLeftSource = new Object[tableSize]; + leftRowSetSource.setArray(destLeftSource); + final Object [] oldRightSource = rightRowSetSource.getArray(); + final Object [] destRightSource = new Object[tableSize]; + rightRowSetSource.setArray(destRightSource); + final long [] oldModifiedCookie = mainCookieSource.getArray(); + final long [] destModifiedCookie = new long[tableSize]; + Arrays.fill(destModifiedCookie, QueryConstants.NULL_LONG); + mainCookieSource.setArray(destModifiedCookie); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final byte currentStateValue = originalStateArray[sourceBucket]; + if (currentStateValue == ENTRY_EMPTY_STATE) { + continue; + } + final byte k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == ENTRY_EMPTY_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftSource[destinationTableLocation] = oldLeftSource[sourceBucket]; + destRightSource[destinationTableLocation] = oldRightSource[sourceBucket]; + destModifiedCookie[destinationTableLocation] = oldModifiedCookie[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherChar.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherChar.java new file mode 100644 index 00000000000..e94767067ce --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherChar.java @@ -0,0 +1,319 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.rightincopen.gen; + +import static io.deephaven.util.compare.CharComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.CharChunk; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.CharChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.ObjectArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableCharArraySource; +import io.deephaven.util.QueryConstants; +import java.lang.Override; +import java.util.Arrays; + +final class RightIncrementalAsOfJoinHasherChar extends RightIncrementalAsOfJoinStateManagerTypedBase { + private ImmutableCharArraySource mainKeySource0; + + private ImmutableCharArraySource alternateKeySource0; + + public RightIncrementalAsOfJoinHasherChar(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableCharArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + private int alternateNextTableLocation(int tableLocation) { + return (tableLocation + 1) & (alternateTableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final CharChunk keyChunk0 = sourceKeyChunks[0].asCharChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final char k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateLeftIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + assert hashSlots != null; + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final CharChunk keyChunk0 = sourceKeyChunks[0].asCharChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final char k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void probeRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final CharChunk keyChunk0 = sourceKeyChunks[0].asCharChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final char k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + boolean found = false; + int tableLocation = firstTableLocation; + byte rowState; + while ((rowState = stateSource.getUnsafe(tableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + found = true; + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + if (!found) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + if (firstAlternateTableLocation < rehashPointer) { + int alternateTableLocation = firstAlternateTableLocation; + while ((rowState = alternateStateSource.getUnsafe(alternateTableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + } + } + } + + private static int hash(char k0) { + int hash = CharChunkHasher.hashInitialSingle(k0); + return hash; + } + + private boolean migrateOneLocation(int locationToMigrate, LongArraySource hashSlots) { + final byte currentStateValue = alternateStateSource.getUnsafe(locationToMigrate); + if (currentStateValue == ENTRY_EMPTY_STATE) { + return false; + } + final char k0 = alternateKeySource0.getUnsafe(locationToMigrate); + final int hash = hash(k0); + int destinationTableLocation = hashToTableLocation(hash); + while (stateSource.getUnsafe(destinationTableLocation) != ENTRY_EMPTY_STATE) { + destinationTableLocation = nextTableLocation(destinationTableLocation); + } + mainKeySource0.set(destinationTableLocation, k0); + stateSource.set(destinationTableLocation, currentStateValue); + leftRowSetSource.set(destinationTableLocation, alternateLeftRowSetSource.getUnsafe(locationToMigrate)); + alternateLeftRowSetSource.set(locationToMigrate, null); + rightRowSetSource.set(destinationTableLocation, alternateRightRowSetSource.getUnsafe(locationToMigrate)); + alternateRightRowSetSource.set(locationToMigrate, null); + final long cookie = alternateCookieSource.getUnsafe(locationToMigrate); + migrateCookie(cookie, destinationTableLocation, hashSlots); + alternateStateSource.set(locationToMigrate, ENTRY_EMPTY_STATE); + return true; + } + + @Override + protected int rehashInternalPartial(int entriesToRehash, LongArraySource hashSlots) { + int rehashedEntries = 0; + while (rehashPointer > 0 && rehashedEntries < entriesToRehash) { + if (migrateOneLocation(--rehashPointer, hashSlots)) { + rehashedEntries++; + } + } + return rehashedEntries; + } + + @Override + protected void newAlternate() { + super.newAlternate(); + this.mainKeySource0 = (ImmutableCharArraySource)super.mainKeySources[0]; + this.alternateKeySource0 = (ImmutableCharArraySource)super.alternateKeySources[0]; + } + + @Override + protected void clearAlternate() { + super.clearAlternate(); + this.alternateKeySource0 = null; + } + + @Override + protected void migrateFront(LongArraySource hashSlots) { + int location = 0; + while (migrateOneLocation(location++, hashSlots)); + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final char[] destKeyArray0 = new char[tableSize]; + final byte[] destState = new byte[tableSize]; + Arrays.fill(destState, ENTRY_EMPTY_STATE); + final char [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final byte [] originalStateArray = stateSource.getArray(); + stateSource.setArray(destState); + final Object [] oldLeftSource = leftRowSetSource.getArray(); + final Object [] destLeftSource = new Object[tableSize]; + leftRowSetSource.setArray(destLeftSource); + final Object [] oldRightSource = rightRowSetSource.getArray(); + final Object [] destRightSource = new Object[tableSize]; + rightRowSetSource.setArray(destRightSource); + final long [] oldModifiedCookie = mainCookieSource.getArray(); + final long [] destModifiedCookie = new long[tableSize]; + Arrays.fill(destModifiedCookie, QueryConstants.NULL_LONG); + mainCookieSource.setArray(destModifiedCookie); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final byte currentStateValue = originalStateArray[sourceBucket]; + if (currentStateValue == ENTRY_EMPTY_STATE) { + continue; + } + final char k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == ENTRY_EMPTY_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftSource[destinationTableLocation] = oldLeftSource[sourceBucket]; + destRightSource[destinationTableLocation] = oldRightSource[sourceBucket]; + destModifiedCookie[destinationTableLocation] = oldModifiedCookie[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherDouble.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherDouble.java new file mode 100644 index 00000000000..6ed4d7b2e93 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherDouble.java @@ -0,0 +1,319 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.rightincopen.gen; + +import static io.deephaven.util.compare.DoubleComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.DoubleChunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.DoubleChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.ObjectArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableDoubleArraySource; +import io.deephaven.util.QueryConstants; +import java.lang.Override; +import java.util.Arrays; + +final class RightIncrementalAsOfJoinHasherDouble extends RightIncrementalAsOfJoinStateManagerTypedBase { + private ImmutableDoubleArraySource mainKeySource0; + + private ImmutableDoubleArraySource alternateKeySource0; + + public RightIncrementalAsOfJoinHasherDouble(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableDoubleArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + private int alternateNextTableLocation(int tableLocation) { + return (tableLocation + 1) & (alternateTableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final DoubleChunk keyChunk0 = sourceKeyChunks[0].asDoubleChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final double k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateLeftIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + assert hashSlots != null; + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final DoubleChunk keyChunk0 = sourceKeyChunks[0].asDoubleChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final double k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void probeRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final DoubleChunk keyChunk0 = sourceKeyChunks[0].asDoubleChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final double k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + boolean found = false; + int tableLocation = firstTableLocation; + byte rowState; + while ((rowState = stateSource.getUnsafe(tableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + found = true; + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + if (!found) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + if (firstAlternateTableLocation < rehashPointer) { + int alternateTableLocation = firstAlternateTableLocation; + while ((rowState = alternateStateSource.getUnsafe(alternateTableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + } + } + } + + private static int hash(double k0) { + int hash = DoubleChunkHasher.hashInitialSingle(k0); + return hash; + } + + private boolean migrateOneLocation(int locationToMigrate, LongArraySource hashSlots) { + final byte currentStateValue = alternateStateSource.getUnsafe(locationToMigrate); + if (currentStateValue == ENTRY_EMPTY_STATE) { + return false; + } + final double k0 = alternateKeySource0.getUnsafe(locationToMigrate); + final int hash = hash(k0); + int destinationTableLocation = hashToTableLocation(hash); + while (stateSource.getUnsafe(destinationTableLocation) != ENTRY_EMPTY_STATE) { + destinationTableLocation = nextTableLocation(destinationTableLocation); + } + mainKeySource0.set(destinationTableLocation, k0); + stateSource.set(destinationTableLocation, currentStateValue); + leftRowSetSource.set(destinationTableLocation, alternateLeftRowSetSource.getUnsafe(locationToMigrate)); + alternateLeftRowSetSource.set(locationToMigrate, null); + rightRowSetSource.set(destinationTableLocation, alternateRightRowSetSource.getUnsafe(locationToMigrate)); + alternateRightRowSetSource.set(locationToMigrate, null); + final long cookie = alternateCookieSource.getUnsafe(locationToMigrate); + migrateCookie(cookie, destinationTableLocation, hashSlots); + alternateStateSource.set(locationToMigrate, ENTRY_EMPTY_STATE); + return true; + } + + @Override + protected int rehashInternalPartial(int entriesToRehash, LongArraySource hashSlots) { + int rehashedEntries = 0; + while (rehashPointer > 0 && rehashedEntries < entriesToRehash) { + if (migrateOneLocation(--rehashPointer, hashSlots)) { + rehashedEntries++; + } + } + return rehashedEntries; + } + + @Override + protected void newAlternate() { + super.newAlternate(); + this.mainKeySource0 = (ImmutableDoubleArraySource)super.mainKeySources[0]; + this.alternateKeySource0 = (ImmutableDoubleArraySource)super.alternateKeySources[0]; + } + + @Override + protected void clearAlternate() { + super.clearAlternate(); + this.alternateKeySource0 = null; + } + + @Override + protected void migrateFront(LongArraySource hashSlots) { + int location = 0; + while (migrateOneLocation(location++, hashSlots)); + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final double[] destKeyArray0 = new double[tableSize]; + final byte[] destState = new byte[tableSize]; + Arrays.fill(destState, ENTRY_EMPTY_STATE); + final double [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final byte [] originalStateArray = stateSource.getArray(); + stateSource.setArray(destState); + final Object [] oldLeftSource = leftRowSetSource.getArray(); + final Object [] destLeftSource = new Object[tableSize]; + leftRowSetSource.setArray(destLeftSource); + final Object [] oldRightSource = rightRowSetSource.getArray(); + final Object [] destRightSource = new Object[tableSize]; + rightRowSetSource.setArray(destRightSource); + final long [] oldModifiedCookie = mainCookieSource.getArray(); + final long [] destModifiedCookie = new long[tableSize]; + Arrays.fill(destModifiedCookie, QueryConstants.NULL_LONG); + mainCookieSource.setArray(destModifiedCookie); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final byte currentStateValue = originalStateArray[sourceBucket]; + if (currentStateValue == ENTRY_EMPTY_STATE) { + continue; + } + final double k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == ENTRY_EMPTY_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftSource[destinationTableLocation] = oldLeftSource[sourceBucket]; + destRightSource[destinationTableLocation] = oldRightSource[sourceBucket]; + destModifiedCookie[destinationTableLocation] = oldModifiedCookie[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherFloat.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherFloat.java new file mode 100644 index 00000000000..0f2413ecd52 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherFloat.java @@ -0,0 +1,319 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.rightincopen.gen; + +import static io.deephaven.util.compare.FloatComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.FloatChunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.FloatChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.ObjectArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableFloatArraySource; +import io.deephaven.util.QueryConstants; +import java.lang.Override; +import java.util.Arrays; + +final class RightIncrementalAsOfJoinHasherFloat extends RightIncrementalAsOfJoinStateManagerTypedBase { + private ImmutableFloatArraySource mainKeySource0; + + private ImmutableFloatArraySource alternateKeySource0; + + public RightIncrementalAsOfJoinHasherFloat(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableFloatArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + private int alternateNextTableLocation(int tableLocation) { + return (tableLocation + 1) & (alternateTableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final FloatChunk keyChunk0 = sourceKeyChunks[0].asFloatChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final float k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateLeftIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + assert hashSlots != null; + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final FloatChunk keyChunk0 = sourceKeyChunks[0].asFloatChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final float k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void probeRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final FloatChunk keyChunk0 = sourceKeyChunks[0].asFloatChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final float k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + boolean found = false; + int tableLocation = firstTableLocation; + byte rowState; + while ((rowState = stateSource.getUnsafe(tableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + found = true; + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + if (!found) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + if (firstAlternateTableLocation < rehashPointer) { + int alternateTableLocation = firstAlternateTableLocation; + while ((rowState = alternateStateSource.getUnsafe(alternateTableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + } + } + } + + private static int hash(float k0) { + int hash = FloatChunkHasher.hashInitialSingle(k0); + return hash; + } + + private boolean migrateOneLocation(int locationToMigrate, LongArraySource hashSlots) { + final byte currentStateValue = alternateStateSource.getUnsafe(locationToMigrate); + if (currentStateValue == ENTRY_EMPTY_STATE) { + return false; + } + final float k0 = alternateKeySource0.getUnsafe(locationToMigrate); + final int hash = hash(k0); + int destinationTableLocation = hashToTableLocation(hash); + while (stateSource.getUnsafe(destinationTableLocation) != ENTRY_EMPTY_STATE) { + destinationTableLocation = nextTableLocation(destinationTableLocation); + } + mainKeySource0.set(destinationTableLocation, k0); + stateSource.set(destinationTableLocation, currentStateValue); + leftRowSetSource.set(destinationTableLocation, alternateLeftRowSetSource.getUnsafe(locationToMigrate)); + alternateLeftRowSetSource.set(locationToMigrate, null); + rightRowSetSource.set(destinationTableLocation, alternateRightRowSetSource.getUnsafe(locationToMigrate)); + alternateRightRowSetSource.set(locationToMigrate, null); + final long cookie = alternateCookieSource.getUnsafe(locationToMigrate); + migrateCookie(cookie, destinationTableLocation, hashSlots); + alternateStateSource.set(locationToMigrate, ENTRY_EMPTY_STATE); + return true; + } + + @Override + protected int rehashInternalPartial(int entriesToRehash, LongArraySource hashSlots) { + int rehashedEntries = 0; + while (rehashPointer > 0 && rehashedEntries < entriesToRehash) { + if (migrateOneLocation(--rehashPointer, hashSlots)) { + rehashedEntries++; + } + } + return rehashedEntries; + } + + @Override + protected void newAlternate() { + super.newAlternate(); + this.mainKeySource0 = (ImmutableFloatArraySource)super.mainKeySources[0]; + this.alternateKeySource0 = (ImmutableFloatArraySource)super.alternateKeySources[0]; + } + + @Override + protected void clearAlternate() { + super.clearAlternate(); + this.alternateKeySource0 = null; + } + + @Override + protected void migrateFront(LongArraySource hashSlots) { + int location = 0; + while (migrateOneLocation(location++, hashSlots)); + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final float[] destKeyArray0 = new float[tableSize]; + final byte[] destState = new byte[tableSize]; + Arrays.fill(destState, ENTRY_EMPTY_STATE); + final float [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final byte [] originalStateArray = stateSource.getArray(); + stateSource.setArray(destState); + final Object [] oldLeftSource = leftRowSetSource.getArray(); + final Object [] destLeftSource = new Object[tableSize]; + leftRowSetSource.setArray(destLeftSource); + final Object [] oldRightSource = rightRowSetSource.getArray(); + final Object [] destRightSource = new Object[tableSize]; + rightRowSetSource.setArray(destRightSource); + final long [] oldModifiedCookie = mainCookieSource.getArray(); + final long [] destModifiedCookie = new long[tableSize]; + Arrays.fill(destModifiedCookie, QueryConstants.NULL_LONG); + mainCookieSource.setArray(destModifiedCookie); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final byte currentStateValue = originalStateArray[sourceBucket]; + if (currentStateValue == ENTRY_EMPTY_STATE) { + continue; + } + final float k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == ENTRY_EMPTY_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftSource[destinationTableLocation] = oldLeftSource[sourceBucket]; + destRightSource[destinationTableLocation] = oldRightSource[sourceBucket]; + destModifiedCookie[destinationTableLocation] = oldModifiedCookie[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherInt.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherInt.java new file mode 100644 index 00000000000..510a07e34b8 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherInt.java @@ -0,0 +1,319 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.rightincopen.gen; + +import static io.deephaven.util.compare.IntComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.IntChunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.IntChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.ObjectArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableIntArraySource; +import io.deephaven.util.QueryConstants; +import java.lang.Override; +import java.util.Arrays; + +final class RightIncrementalAsOfJoinHasherInt extends RightIncrementalAsOfJoinStateManagerTypedBase { + private ImmutableIntArraySource mainKeySource0; + + private ImmutableIntArraySource alternateKeySource0; + + public RightIncrementalAsOfJoinHasherInt(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableIntArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + private int alternateNextTableLocation(int tableLocation) { + return (tableLocation + 1) & (alternateTableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final IntChunk keyChunk0 = sourceKeyChunks[0].asIntChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final int k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateLeftIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + assert hashSlots != null; + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final IntChunk keyChunk0 = sourceKeyChunks[0].asIntChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final int k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void probeRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final IntChunk keyChunk0 = sourceKeyChunks[0].asIntChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final int k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + boolean found = false; + int tableLocation = firstTableLocation; + byte rowState; + while ((rowState = stateSource.getUnsafe(tableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + found = true; + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + if (!found) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + if (firstAlternateTableLocation < rehashPointer) { + int alternateTableLocation = firstAlternateTableLocation; + while ((rowState = alternateStateSource.getUnsafe(alternateTableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + } + } + } + + private static int hash(int k0) { + int hash = IntChunkHasher.hashInitialSingle(k0); + return hash; + } + + private boolean migrateOneLocation(int locationToMigrate, LongArraySource hashSlots) { + final byte currentStateValue = alternateStateSource.getUnsafe(locationToMigrate); + if (currentStateValue == ENTRY_EMPTY_STATE) { + return false; + } + final int k0 = alternateKeySource0.getUnsafe(locationToMigrate); + final int hash = hash(k0); + int destinationTableLocation = hashToTableLocation(hash); + while (stateSource.getUnsafe(destinationTableLocation) != ENTRY_EMPTY_STATE) { + destinationTableLocation = nextTableLocation(destinationTableLocation); + } + mainKeySource0.set(destinationTableLocation, k0); + stateSource.set(destinationTableLocation, currentStateValue); + leftRowSetSource.set(destinationTableLocation, alternateLeftRowSetSource.getUnsafe(locationToMigrate)); + alternateLeftRowSetSource.set(locationToMigrate, null); + rightRowSetSource.set(destinationTableLocation, alternateRightRowSetSource.getUnsafe(locationToMigrate)); + alternateRightRowSetSource.set(locationToMigrate, null); + final long cookie = alternateCookieSource.getUnsafe(locationToMigrate); + migrateCookie(cookie, destinationTableLocation, hashSlots); + alternateStateSource.set(locationToMigrate, ENTRY_EMPTY_STATE); + return true; + } + + @Override + protected int rehashInternalPartial(int entriesToRehash, LongArraySource hashSlots) { + int rehashedEntries = 0; + while (rehashPointer > 0 && rehashedEntries < entriesToRehash) { + if (migrateOneLocation(--rehashPointer, hashSlots)) { + rehashedEntries++; + } + } + return rehashedEntries; + } + + @Override + protected void newAlternate() { + super.newAlternate(); + this.mainKeySource0 = (ImmutableIntArraySource)super.mainKeySources[0]; + this.alternateKeySource0 = (ImmutableIntArraySource)super.alternateKeySources[0]; + } + + @Override + protected void clearAlternate() { + super.clearAlternate(); + this.alternateKeySource0 = null; + } + + @Override + protected void migrateFront(LongArraySource hashSlots) { + int location = 0; + while (migrateOneLocation(location++, hashSlots)); + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final int[] destKeyArray0 = new int[tableSize]; + final byte[] destState = new byte[tableSize]; + Arrays.fill(destState, ENTRY_EMPTY_STATE); + final int [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final byte [] originalStateArray = stateSource.getArray(); + stateSource.setArray(destState); + final Object [] oldLeftSource = leftRowSetSource.getArray(); + final Object [] destLeftSource = new Object[tableSize]; + leftRowSetSource.setArray(destLeftSource); + final Object [] oldRightSource = rightRowSetSource.getArray(); + final Object [] destRightSource = new Object[tableSize]; + rightRowSetSource.setArray(destRightSource); + final long [] oldModifiedCookie = mainCookieSource.getArray(); + final long [] destModifiedCookie = new long[tableSize]; + Arrays.fill(destModifiedCookie, QueryConstants.NULL_LONG); + mainCookieSource.setArray(destModifiedCookie); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final byte currentStateValue = originalStateArray[sourceBucket]; + if (currentStateValue == ENTRY_EMPTY_STATE) { + continue; + } + final int k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == ENTRY_EMPTY_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftSource[destinationTableLocation] = oldLeftSource[sourceBucket]; + destRightSource[destinationTableLocation] = oldRightSource[sourceBucket]; + destModifiedCookie[destinationTableLocation] = oldModifiedCookie[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherLong.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherLong.java new file mode 100644 index 00000000000..5333696c4eb --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherLong.java @@ -0,0 +1,318 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.rightincopen.gen; + +import static io.deephaven.util.compare.LongComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.LongChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.ObjectArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableLongArraySource; +import io.deephaven.util.QueryConstants; +import java.lang.Override; +import java.util.Arrays; + +final class RightIncrementalAsOfJoinHasherLong extends RightIncrementalAsOfJoinStateManagerTypedBase { + private ImmutableLongArraySource mainKeySource0; + + private ImmutableLongArraySource alternateKeySource0; + + public RightIncrementalAsOfJoinHasherLong(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableLongArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + private int alternateNextTableLocation(int tableLocation) { + return (tableLocation + 1) & (alternateTableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final LongChunk keyChunk0 = sourceKeyChunks[0].asLongChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final long k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateLeftIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + assert hashSlots != null; + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final LongChunk keyChunk0 = sourceKeyChunks[0].asLongChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final long k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void probeRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final LongChunk keyChunk0 = sourceKeyChunks[0].asLongChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final long k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + boolean found = false; + int tableLocation = firstTableLocation; + byte rowState; + while ((rowState = stateSource.getUnsafe(tableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + found = true; + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + if (!found) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + if (firstAlternateTableLocation < rehashPointer) { + int alternateTableLocation = firstAlternateTableLocation; + while ((rowState = alternateStateSource.getUnsafe(alternateTableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + } + } + } + + private static int hash(long k0) { + int hash = LongChunkHasher.hashInitialSingle(k0); + return hash; + } + + private boolean migrateOneLocation(int locationToMigrate, LongArraySource hashSlots) { + final byte currentStateValue = alternateStateSource.getUnsafe(locationToMigrate); + if (currentStateValue == ENTRY_EMPTY_STATE) { + return false; + } + final long k0 = alternateKeySource0.getUnsafe(locationToMigrate); + final int hash = hash(k0); + int destinationTableLocation = hashToTableLocation(hash); + while (stateSource.getUnsafe(destinationTableLocation) != ENTRY_EMPTY_STATE) { + destinationTableLocation = nextTableLocation(destinationTableLocation); + } + mainKeySource0.set(destinationTableLocation, k0); + stateSource.set(destinationTableLocation, currentStateValue); + leftRowSetSource.set(destinationTableLocation, alternateLeftRowSetSource.getUnsafe(locationToMigrate)); + alternateLeftRowSetSource.set(locationToMigrate, null); + rightRowSetSource.set(destinationTableLocation, alternateRightRowSetSource.getUnsafe(locationToMigrate)); + alternateRightRowSetSource.set(locationToMigrate, null); + final long cookie = alternateCookieSource.getUnsafe(locationToMigrate); + migrateCookie(cookie, destinationTableLocation, hashSlots); + alternateStateSource.set(locationToMigrate, ENTRY_EMPTY_STATE); + return true; + } + + @Override + protected int rehashInternalPartial(int entriesToRehash, LongArraySource hashSlots) { + int rehashedEntries = 0; + while (rehashPointer > 0 && rehashedEntries < entriesToRehash) { + if (migrateOneLocation(--rehashPointer, hashSlots)) { + rehashedEntries++; + } + } + return rehashedEntries; + } + + @Override + protected void newAlternate() { + super.newAlternate(); + this.mainKeySource0 = (ImmutableLongArraySource)super.mainKeySources[0]; + this.alternateKeySource0 = (ImmutableLongArraySource)super.alternateKeySources[0]; + } + + @Override + protected void clearAlternate() { + super.clearAlternate(); + this.alternateKeySource0 = null; + } + + @Override + protected void migrateFront(LongArraySource hashSlots) { + int location = 0; + while (migrateOneLocation(location++, hashSlots)); + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final long[] destKeyArray0 = new long[tableSize]; + final byte[] destState = new byte[tableSize]; + Arrays.fill(destState, ENTRY_EMPTY_STATE); + final long [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final byte [] originalStateArray = stateSource.getArray(); + stateSource.setArray(destState); + final Object [] oldLeftSource = leftRowSetSource.getArray(); + final Object [] destLeftSource = new Object[tableSize]; + leftRowSetSource.setArray(destLeftSource); + final Object [] oldRightSource = rightRowSetSource.getArray(); + final Object [] destRightSource = new Object[tableSize]; + rightRowSetSource.setArray(destRightSource); + final long [] oldModifiedCookie = mainCookieSource.getArray(); + final long [] destModifiedCookie = new long[tableSize]; + Arrays.fill(destModifiedCookie, QueryConstants.NULL_LONG); + mainCookieSource.setArray(destModifiedCookie); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final byte currentStateValue = originalStateArray[sourceBucket]; + if (currentStateValue == ENTRY_EMPTY_STATE) { + continue; + } + final long k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == ENTRY_EMPTY_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftSource[destinationTableLocation] = oldLeftSource[sourceBucket]; + destRightSource[destinationTableLocation] = oldRightSource[sourceBucket]; + destModifiedCookie[destinationTableLocation] = oldModifiedCookie[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherObject.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherObject.java new file mode 100644 index 00000000000..19a3d59ddfd --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherObject.java @@ -0,0 +1,321 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.rightincopen.gen; + +import static io.deephaven.util.compare.ObjectComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.ObjectChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.ObjectChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.ObjectArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableObjectArraySource; +import io.deephaven.util.QueryConstants; +import java.lang.Object; +import java.lang.Override; +import java.util.Arrays; + +final class RightIncrementalAsOfJoinHasherObject extends RightIncrementalAsOfJoinStateManagerTypedBase { + private ImmutableObjectArraySource mainKeySource0; + + private ImmutableObjectArraySource alternateKeySource0; + + public RightIncrementalAsOfJoinHasherObject(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableObjectArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + private int alternateNextTableLocation(int tableLocation) { + return (tableLocation + 1) & (alternateTableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final ObjectChunk keyChunk0 = sourceKeyChunks[0].asObjectChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final Object k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateLeftIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + assert hashSlots != null; + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final ObjectChunk keyChunk0 = sourceKeyChunks[0].asObjectChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final Object k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void probeRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final ObjectChunk keyChunk0 = sourceKeyChunks[0].asObjectChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final Object k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + boolean found = false; + int tableLocation = firstTableLocation; + byte rowState; + while ((rowState = stateSource.getUnsafe(tableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + found = true; + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + if (!found) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + if (firstAlternateTableLocation < rehashPointer) { + int alternateTableLocation = firstAlternateTableLocation; + while ((rowState = alternateStateSource.getUnsafe(alternateTableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + } + } + } + + private static int hash(Object k0) { + int hash = ObjectChunkHasher.hashInitialSingle(k0); + return hash; + } + + private boolean migrateOneLocation(int locationToMigrate, LongArraySource hashSlots) { + final byte currentStateValue = alternateStateSource.getUnsafe(locationToMigrate); + if (currentStateValue == ENTRY_EMPTY_STATE) { + return false; + } + final Object k0 = alternateKeySource0.getUnsafe(locationToMigrate); + final int hash = hash(k0); + int destinationTableLocation = hashToTableLocation(hash); + while (stateSource.getUnsafe(destinationTableLocation) != ENTRY_EMPTY_STATE) { + destinationTableLocation = nextTableLocation(destinationTableLocation); + } + mainKeySource0.set(destinationTableLocation, k0); + alternateKeySource0.set(locationToMigrate, null); + stateSource.set(destinationTableLocation, currentStateValue); + leftRowSetSource.set(destinationTableLocation, alternateLeftRowSetSource.getUnsafe(locationToMigrate)); + alternateLeftRowSetSource.set(locationToMigrate, null); + rightRowSetSource.set(destinationTableLocation, alternateRightRowSetSource.getUnsafe(locationToMigrate)); + alternateRightRowSetSource.set(locationToMigrate, null); + final long cookie = alternateCookieSource.getUnsafe(locationToMigrate); + migrateCookie(cookie, destinationTableLocation, hashSlots); + alternateStateSource.set(locationToMigrate, ENTRY_EMPTY_STATE); + return true; + } + + @Override + protected int rehashInternalPartial(int entriesToRehash, LongArraySource hashSlots) { + int rehashedEntries = 0; + while (rehashPointer > 0 && rehashedEntries < entriesToRehash) { + if (migrateOneLocation(--rehashPointer, hashSlots)) { + rehashedEntries++; + } + } + return rehashedEntries; + } + + @Override + protected void newAlternate() { + super.newAlternate(); + this.mainKeySource0 = (ImmutableObjectArraySource)super.mainKeySources[0]; + this.alternateKeySource0 = (ImmutableObjectArraySource)super.alternateKeySources[0]; + } + + @Override + protected void clearAlternate() { + super.clearAlternate(); + this.alternateKeySource0 = null; + } + + @Override + protected void migrateFront(LongArraySource hashSlots) { + int location = 0; + while (migrateOneLocation(location++, hashSlots)); + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final Object[] destKeyArray0 = new Object[tableSize]; + final byte[] destState = new byte[tableSize]; + Arrays.fill(destState, ENTRY_EMPTY_STATE); + final Object [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final byte [] originalStateArray = stateSource.getArray(); + stateSource.setArray(destState); + final Object [] oldLeftSource = leftRowSetSource.getArray(); + final Object [] destLeftSource = new Object[tableSize]; + leftRowSetSource.setArray(destLeftSource); + final Object [] oldRightSource = rightRowSetSource.getArray(); + final Object [] destRightSource = new Object[tableSize]; + rightRowSetSource.setArray(destRightSource); + final long [] oldModifiedCookie = mainCookieSource.getArray(); + final long [] destModifiedCookie = new long[tableSize]; + Arrays.fill(destModifiedCookie, QueryConstants.NULL_LONG); + mainCookieSource.setArray(destModifiedCookie); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final byte currentStateValue = originalStateArray[sourceBucket]; + if (currentStateValue == ENTRY_EMPTY_STATE) { + continue; + } + final Object k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == ENTRY_EMPTY_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftSource[destinationTableLocation] = oldLeftSource[sourceBucket]; + destRightSource[destinationTableLocation] = oldRightSource[sourceBucket]; + destModifiedCookie[destinationTableLocation] = oldModifiedCookie[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherShort.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherShort.java new file mode 100644 index 00000000000..01d678fa0e5 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/RightIncrementalAsOfJoinHasherShort.java @@ -0,0 +1,319 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.rightincopen.gen; + +import static io.deephaven.util.compare.ShortComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.ShortChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.ShortChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.ObjectArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableShortArraySource; +import io.deephaven.util.QueryConstants; +import java.lang.Override; +import java.util.Arrays; + +final class RightIncrementalAsOfJoinHasherShort extends RightIncrementalAsOfJoinStateManagerTypedBase { + private ImmutableShortArraySource mainKeySource0; + + private ImmutableShortArraySource alternateKeySource0; + + public RightIncrementalAsOfJoinHasherShort(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableShortArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + private int alternateNextTableLocation(int tableLocation) { + return (tableLocation + 1) & (alternateTableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final ShortChunk keyChunk0 = sourceKeyChunks[0].asShortChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final short k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateLeftIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + assert hashSlots != null; + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final ShortChunk keyChunk0 = sourceKeyChunks[0].asShortChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final short k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + MAIN_SEARCH: while (true) { + byte rowState = stateSource.getUnsafe(tableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + int alternateTableLocation = firstAlternateTableLocation; + while (alternateTableLocation < rehashPointer) { + rowState = alternateStateSource.getUnsafe(alternateTableLocation); + if (rowState == ENTRY_EMPTY_STATE) { + break; + } else if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break MAIN_SEARCH; + } else { + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + numEntries++; + mainKeySource0.set(tableLocation, k0); + final long cookie = makeCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + stateSource.set(tableLocation, (byte)(ENTRY_RIGHT_IS_EMPTY | ENTRY_LEFT_IS_EMPTY)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), (byte) 0); + } + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + if (sequentialBuilders != null) { + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void probeRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, ObjectArraySource sequentialBuilders) { + final ShortChunk keyChunk0 = sourceKeyChunks[0].asShortChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final short k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + boolean found = false; + int tableLocation = firstTableLocation; + byte rowState; + while ((rowState = stateSource.getUnsafe(tableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieMain(tableLocation); + hashSlots.set(cookie, (long)tableLocation | mainInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + found = true; + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + if (!found) { + final int firstAlternateTableLocation = hashToTableLocationAlternate(hash); + if (firstAlternateTableLocation < rehashPointer) { + int alternateTableLocation = firstAlternateTableLocation; + while ((rowState = alternateStateSource.getUnsafe(alternateTableLocation)) != ENTRY_EMPTY_STATE) { + if (eq(alternateKeySource0.getUnsafe(alternateTableLocation), k0)) { + if (sequentialBuilders != null) { + final long cookie = getCookieAlternate(alternateTableLocation); + hashSlots.set(cookie, (long)alternateTableLocation | alternateInsertMask); + addToSequentialBuilder(cookie, sequentialBuilders, rowKeyChunk.get(chunkPosition)); + } else { + addAlternateRightIndex(alternateTableLocation, rowKeyChunk.get(chunkPosition), rowState); + } + break; + } + alternateTableLocation = alternateNextTableLocation(alternateTableLocation); + Assert.neq(alternateTableLocation, "alternateTableLocation", firstAlternateTableLocation, "firstAlternateTableLocation"); + } + } + } + } + } + + private static int hash(short k0) { + int hash = ShortChunkHasher.hashInitialSingle(k0); + return hash; + } + + private boolean migrateOneLocation(int locationToMigrate, LongArraySource hashSlots) { + final byte currentStateValue = alternateStateSource.getUnsafe(locationToMigrate); + if (currentStateValue == ENTRY_EMPTY_STATE) { + return false; + } + final short k0 = alternateKeySource0.getUnsafe(locationToMigrate); + final int hash = hash(k0); + int destinationTableLocation = hashToTableLocation(hash); + while (stateSource.getUnsafe(destinationTableLocation) != ENTRY_EMPTY_STATE) { + destinationTableLocation = nextTableLocation(destinationTableLocation); + } + mainKeySource0.set(destinationTableLocation, k0); + stateSource.set(destinationTableLocation, currentStateValue); + leftRowSetSource.set(destinationTableLocation, alternateLeftRowSetSource.getUnsafe(locationToMigrate)); + alternateLeftRowSetSource.set(locationToMigrate, null); + rightRowSetSource.set(destinationTableLocation, alternateRightRowSetSource.getUnsafe(locationToMigrate)); + alternateRightRowSetSource.set(locationToMigrate, null); + final long cookie = alternateCookieSource.getUnsafe(locationToMigrate); + migrateCookie(cookie, destinationTableLocation, hashSlots); + alternateStateSource.set(locationToMigrate, ENTRY_EMPTY_STATE); + return true; + } + + @Override + protected int rehashInternalPartial(int entriesToRehash, LongArraySource hashSlots) { + int rehashedEntries = 0; + while (rehashPointer > 0 && rehashedEntries < entriesToRehash) { + if (migrateOneLocation(--rehashPointer, hashSlots)) { + rehashedEntries++; + } + } + return rehashedEntries; + } + + @Override + protected void newAlternate() { + super.newAlternate(); + this.mainKeySource0 = (ImmutableShortArraySource)super.mainKeySources[0]; + this.alternateKeySource0 = (ImmutableShortArraySource)super.alternateKeySources[0]; + } + + @Override + protected void clearAlternate() { + super.clearAlternate(); + this.alternateKeySource0 = null; + } + + @Override + protected void migrateFront(LongArraySource hashSlots) { + int location = 0; + while (migrateOneLocation(location++, hashSlots)); + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final short[] destKeyArray0 = new short[tableSize]; + final byte[] destState = new byte[tableSize]; + Arrays.fill(destState, ENTRY_EMPTY_STATE); + final short [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final byte [] originalStateArray = stateSource.getArray(); + stateSource.setArray(destState); + final Object [] oldLeftSource = leftRowSetSource.getArray(); + final Object [] destLeftSource = new Object[tableSize]; + leftRowSetSource.setArray(destLeftSource); + final Object [] oldRightSource = rightRowSetSource.getArray(); + final Object [] destRightSource = new Object[tableSize]; + rightRowSetSource.setArray(destRightSource); + final long [] oldModifiedCookie = mainCookieSource.getArray(); + final long [] destModifiedCookie = new long[tableSize]; + Arrays.fill(destModifiedCookie, QueryConstants.NULL_LONG); + mainCookieSource.setArray(destModifiedCookie); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final byte currentStateValue = originalStateArray[sourceBucket]; + if (currentStateValue == ENTRY_EMPTY_STATE) { + continue; + } + final short k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == ENTRY_EMPTY_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftSource[destinationTableLocation] = oldLeftSource[sourceBucket]; + destRightSource[destinationTableLocation] = oldRightSource[sourceBucket]; + destModifiedCookie[destinationTableLocation] = oldModifiedCookie[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/TypedHashDispatcher.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/TypedHashDispatcher.java new file mode 100644 index 00000000000..9802140ae40 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/rightincopen/gen/TypedHashDispatcher.java @@ -0,0 +1,43 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.replicators.ReplicateTypedHashers +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.rightincopen.gen; + +import io.deephaven.chunk.ChunkType; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalAsOfJoinStateManagerTypedBase; +import java.util.Arrays; + +/** + * The TypedHashDispatcher returns a pre-generated and precompiled hasher instance suitable for the provided column sources, or null if there is not a precompiled hasher suitable for the specified sources. */ +public class TypedHashDispatcher { + private TypedHashDispatcher() { + // static use only + } + + public static RightIncrementalAsOfJoinStateManagerTypedBase dispatch(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + final ChunkType[] chunkTypes = Arrays.stream(tableKeySources).map(ColumnSource::getChunkType).toArray(ChunkType[]::new);; + if (chunkTypes.length == 1) { + return dispatchSingle(chunkTypes[0], tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + } + return null; + } + + private static RightIncrementalAsOfJoinStateManagerTypedBase dispatchSingle(ChunkType chunkType, + ColumnSource[] tableKeySources, ColumnSource[] originalTableKeySources, int tableSize, + double maximumLoadFactor, double targetLoadFactor) { + switch (chunkType) { + default: throw new UnsupportedOperationException("Invalid chunk type for typed hashers: " + chunkType); + case Char: return new RightIncrementalAsOfJoinHasherChar(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Byte: return new RightIncrementalAsOfJoinHasherByte(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Short: return new RightIncrementalAsOfJoinHasherShort(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Int: return new RightIncrementalAsOfJoinHasherInt(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Long: return new RightIncrementalAsOfJoinHasherLong(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Float: return new RightIncrementalAsOfJoinHasherFloat(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Double: return new RightIncrementalAsOfJoinHasherDouble(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Object: return new RightIncrementalAsOfJoinHasherObject(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherByte.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherByte.java new file mode 100644 index 00000000000..052ed6b67f6 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherByte.java @@ -0,0 +1,181 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.staticopen.gen; + +import static io.deephaven.util.compare.ByteComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.ByteChunk; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.ByteChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.RowSetBuilderRandom; +import io.deephaven.engine.rowset.RowSetFactory; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.StaticAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableByteArraySource; +import java.lang.Object; +import java.lang.Override; +import java.util.Arrays; +import org.apache.commons.lang3.mutable.MutableInt; + +final class StaticAsOfJoinHasherByte extends StaticAsOfJoinStateManagerTypedBase { + private final ImmutableByteArraySource mainKeySource0; + + public StaticAsOfJoinHasherByte(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableByteArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final ByteChunk keyChunk0 = sourceKeyChunks[0].asByteChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final byte k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + rightRowSetSource.set(tableLocation, RowSetFactory.builderSequential()); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final ByteChunk keyChunk0 = sourceKeyChunks[0].asByteChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final byte k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void decorateLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, MutableInt hashSlotOffset, + RowSetBuilderRandom foundBuilder) { + final ByteChunk keyChunk0 = sourceKeyChunks[0].asByteChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final byte k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long indexKey = rowKeyChunk.get(chunkPosition); + if (addLeftIndex(tableLocation, indexKey) && hashSlots != null) { + hashSlots.set(hashSlotOffset.getAndIncrement(), (long)tableLocation); + foundBuilder.addKey(indexKey); + } + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + protected void decorateWithRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final ByteChunk keyChunk0 = sourceKeyChunks[0].asByteChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final byte k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + private static int hash(byte k0) { + int hash = ByteChunkHasher.hashInitialSingle(k0); + return hash; + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final byte[] destKeyArray0 = new byte[tableSize]; + final Object[] destState = new Object[tableSize]; + Arrays.fill(destState, EMPTY_RIGHT_STATE); + final byte [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final Object [] originalStateArray = (Object[])rightRowSetSource.getArray(); + rightRowSetSource.setArray(destState); + final Object [] oldLeftState = leftRowSetSource.getArray(); + final Object [] destLeftState = new Object[tableSize]; + leftRowSetSource.setArray(destLeftState); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final Object currentStateValue = (Object)originalStateArray[sourceBucket]; + if (currentStateValue == EMPTY_RIGHT_STATE) { + continue; + } + final byte k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == EMPTY_RIGHT_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftState[destinationTableLocation] = oldLeftState[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherChar.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherChar.java new file mode 100644 index 00000000000..17824945283 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherChar.java @@ -0,0 +1,181 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.staticopen.gen; + +import static io.deephaven.util.compare.CharComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.CharChunk; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.CharChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.RowSetBuilderRandom; +import io.deephaven.engine.rowset.RowSetFactory; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.StaticAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableCharArraySource; +import java.lang.Object; +import java.lang.Override; +import java.util.Arrays; +import org.apache.commons.lang3.mutable.MutableInt; + +final class StaticAsOfJoinHasherChar extends StaticAsOfJoinStateManagerTypedBase { + private final ImmutableCharArraySource mainKeySource0; + + public StaticAsOfJoinHasherChar(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableCharArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final CharChunk keyChunk0 = sourceKeyChunks[0].asCharChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final char k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + rightRowSetSource.set(tableLocation, RowSetFactory.builderSequential()); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final CharChunk keyChunk0 = sourceKeyChunks[0].asCharChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final char k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void decorateLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, MutableInt hashSlotOffset, + RowSetBuilderRandom foundBuilder) { + final CharChunk keyChunk0 = sourceKeyChunks[0].asCharChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final char k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long indexKey = rowKeyChunk.get(chunkPosition); + if (addLeftIndex(tableLocation, indexKey) && hashSlots != null) { + hashSlots.set(hashSlotOffset.getAndIncrement(), (long)tableLocation); + foundBuilder.addKey(indexKey); + } + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + protected void decorateWithRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final CharChunk keyChunk0 = sourceKeyChunks[0].asCharChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final char k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + private static int hash(char k0) { + int hash = CharChunkHasher.hashInitialSingle(k0); + return hash; + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final char[] destKeyArray0 = new char[tableSize]; + final Object[] destState = new Object[tableSize]; + Arrays.fill(destState, EMPTY_RIGHT_STATE); + final char [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final Object [] originalStateArray = (Object[])rightRowSetSource.getArray(); + rightRowSetSource.setArray(destState); + final Object [] oldLeftState = leftRowSetSource.getArray(); + final Object [] destLeftState = new Object[tableSize]; + leftRowSetSource.setArray(destLeftState); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final Object currentStateValue = (Object)originalStateArray[sourceBucket]; + if (currentStateValue == EMPTY_RIGHT_STATE) { + continue; + } + final char k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == EMPTY_RIGHT_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftState[destinationTableLocation] = oldLeftState[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherDouble.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherDouble.java new file mode 100644 index 00000000000..da0fb1c3ee3 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherDouble.java @@ -0,0 +1,181 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.staticopen.gen; + +import static io.deephaven.util.compare.DoubleComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.DoubleChunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.DoubleChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.RowSetBuilderRandom; +import io.deephaven.engine.rowset.RowSetFactory; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.StaticAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableDoubleArraySource; +import java.lang.Object; +import java.lang.Override; +import java.util.Arrays; +import org.apache.commons.lang3.mutable.MutableInt; + +final class StaticAsOfJoinHasherDouble extends StaticAsOfJoinStateManagerTypedBase { + private final ImmutableDoubleArraySource mainKeySource0; + + public StaticAsOfJoinHasherDouble(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableDoubleArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final DoubleChunk keyChunk0 = sourceKeyChunks[0].asDoubleChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final double k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + rightRowSetSource.set(tableLocation, RowSetFactory.builderSequential()); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final DoubleChunk keyChunk0 = sourceKeyChunks[0].asDoubleChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final double k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void decorateLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, MutableInt hashSlotOffset, + RowSetBuilderRandom foundBuilder) { + final DoubleChunk keyChunk0 = sourceKeyChunks[0].asDoubleChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final double k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long indexKey = rowKeyChunk.get(chunkPosition); + if (addLeftIndex(tableLocation, indexKey) && hashSlots != null) { + hashSlots.set(hashSlotOffset.getAndIncrement(), (long)tableLocation); + foundBuilder.addKey(indexKey); + } + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + protected void decorateWithRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final DoubleChunk keyChunk0 = sourceKeyChunks[0].asDoubleChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final double k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + private static int hash(double k0) { + int hash = DoubleChunkHasher.hashInitialSingle(k0); + return hash; + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final double[] destKeyArray0 = new double[tableSize]; + final Object[] destState = new Object[tableSize]; + Arrays.fill(destState, EMPTY_RIGHT_STATE); + final double [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final Object [] originalStateArray = (Object[])rightRowSetSource.getArray(); + rightRowSetSource.setArray(destState); + final Object [] oldLeftState = leftRowSetSource.getArray(); + final Object [] destLeftState = new Object[tableSize]; + leftRowSetSource.setArray(destLeftState); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final Object currentStateValue = (Object)originalStateArray[sourceBucket]; + if (currentStateValue == EMPTY_RIGHT_STATE) { + continue; + } + final double k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == EMPTY_RIGHT_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftState[destinationTableLocation] = oldLeftState[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherFloat.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherFloat.java new file mode 100644 index 00000000000..f31d17923be --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherFloat.java @@ -0,0 +1,181 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.staticopen.gen; + +import static io.deephaven.util.compare.FloatComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.FloatChunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.FloatChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.RowSetBuilderRandom; +import io.deephaven.engine.rowset.RowSetFactory; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.StaticAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableFloatArraySource; +import java.lang.Object; +import java.lang.Override; +import java.util.Arrays; +import org.apache.commons.lang3.mutable.MutableInt; + +final class StaticAsOfJoinHasherFloat extends StaticAsOfJoinStateManagerTypedBase { + private final ImmutableFloatArraySource mainKeySource0; + + public StaticAsOfJoinHasherFloat(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableFloatArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final FloatChunk keyChunk0 = sourceKeyChunks[0].asFloatChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final float k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + rightRowSetSource.set(tableLocation, RowSetFactory.builderSequential()); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final FloatChunk keyChunk0 = sourceKeyChunks[0].asFloatChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final float k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void decorateLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, MutableInt hashSlotOffset, + RowSetBuilderRandom foundBuilder) { + final FloatChunk keyChunk0 = sourceKeyChunks[0].asFloatChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final float k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long indexKey = rowKeyChunk.get(chunkPosition); + if (addLeftIndex(tableLocation, indexKey) && hashSlots != null) { + hashSlots.set(hashSlotOffset.getAndIncrement(), (long)tableLocation); + foundBuilder.addKey(indexKey); + } + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + protected void decorateWithRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final FloatChunk keyChunk0 = sourceKeyChunks[0].asFloatChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final float k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + private static int hash(float k0) { + int hash = FloatChunkHasher.hashInitialSingle(k0); + return hash; + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final float[] destKeyArray0 = new float[tableSize]; + final Object[] destState = new Object[tableSize]; + Arrays.fill(destState, EMPTY_RIGHT_STATE); + final float [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final Object [] originalStateArray = (Object[])rightRowSetSource.getArray(); + rightRowSetSource.setArray(destState); + final Object [] oldLeftState = leftRowSetSource.getArray(); + final Object [] destLeftState = new Object[tableSize]; + leftRowSetSource.setArray(destLeftState); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final Object currentStateValue = (Object)originalStateArray[sourceBucket]; + if (currentStateValue == EMPTY_RIGHT_STATE) { + continue; + } + final float k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == EMPTY_RIGHT_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftState[destinationTableLocation] = oldLeftState[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherInt.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherInt.java new file mode 100644 index 00000000000..386d65110e4 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherInt.java @@ -0,0 +1,181 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.staticopen.gen; + +import static io.deephaven.util.compare.IntComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.IntChunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.IntChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.RowSetBuilderRandom; +import io.deephaven.engine.rowset.RowSetFactory; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.StaticAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableIntArraySource; +import java.lang.Object; +import java.lang.Override; +import java.util.Arrays; +import org.apache.commons.lang3.mutable.MutableInt; + +final class StaticAsOfJoinHasherInt extends StaticAsOfJoinStateManagerTypedBase { + private final ImmutableIntArraySource mainKeySource0; + + public StaticAsOfJoinHasherInt(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableIntArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final IntChunk keyChunk0 = sourceKeyChunks[0].asIntChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final int k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + rightRowSetSource.set(tableLocation, RowSetFactory.builderSequential()); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final IntChunk keyChunk0 = sourceKeyChunks[0].asIntChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final int k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void decorateLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, MutableInt hashSlotOffset, + RowSetBuilderRandom foundBuilder) { + final IntChunk keyChunk0 = sourceKeyChunks[0].asIntChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final int k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long indexKey = rowKeyChunk.get(chunkPosition); + if (addLeftIndex(tableLocation, indexKey) && hashSlots != null) { + hashSlots.set(hashSlotOffset.getAndIncrement(), (long)tableLocation); + foundBuilder.addKey(indexKey); + } + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + protected void decorateWithRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final IntChunk keyChunk0 = sourceKeyChunks[0].asIntChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final int k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + private static int hash(int k0) { + int hash = IntChunkHasher.hashInitialSingle(k0); + return hash; + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final int[] destKeyArray0 = new int[tableSize]; + final Object[] destState = new Object[tableSize]; + Arrays.fill(destState, EMPTY_RIGHT_STATE); + final int [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final Object [] originalStateArray = (Object[])rightRowSetSource.getArray(); + rightRowSetSource.setArray(destState); + final Object [] oldLeftState = leftRowSetSource.getArray(); + final Object [] destLeftState = new Object[tableSize]; + leftRowSetSource.setArray(destLeftState); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final Object currentStateValue = (Object)originalStateArray[sourceBucket]; + if (currentStateValue == EMPTY_RIGHT_STATE) { + continue; + } + final int k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == EMPTY_RIGHT_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftState[destinationTableLocation] = oldLeftState[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherLong.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherLong.java new file mode 100644 index 00000000000..22ca3935651 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherLong.java @@ -0,0 +1,180 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.staticopen.gen; + +import static io.deephaven.util.compare.LongComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.LongChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.RowSetBuilderRandom; +import io.deephaven.engine.rowset.RowSetFactory; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.StaticAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableLongArraySource; +import java.lang.Object; +import java.lang.Override; +import java.util.Arrays; +import org.apache.commons.lang3.mutable.MutableInt; + +final class StaticAsOfJoinHasherLong extends StaticAsOfJoinStateManagerTypedBase { + private final ImmutableLongArraySource mainKeySource0; + + public StaticAsOfJoinHasherLong(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableLongArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final LongChunk keyChunk0 = sourceKeyChunks[0].asLongChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final long k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + rightRowSetSource.set(tableLocation, RowSetFactory.builderSequential()); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final LongChunk keyChunk0 = sourceKeyChunks[0].asLongChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final long k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void decorateLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, MutableInt hashSlotOffset, + RowSetBuilderRandom foundBuilder) { + final LongChunk keyChunk0 = sourceKeyChunks[0].asLongChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final long k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long indexKey = rowKeyChunk.get(chunkPosition); + if (addLeftIndex(tableLocation, indexKey) && hashSlots != null) { + hashSlots.set(hashSlotOffset.getAndIncrement(), (long)tableLocation); + foundBuilder.addKey(indexKey); + } + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + protected void decorateWithRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final LongChunk keyChunk0 = sourceKeyChunks[0].asLongChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final long k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + private static int hash(long k0) { + int hash = LongChunkHasher.hashInitialSingle(k0); + return hash; + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final long[] destKeyArray0 = new long[tableSize]; + final Object[] destState = new Object[tableSize]; + Arrays.fill(destState, EMPTY_RIGHT_STATE); + final long [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final Object [] originalStateArray = (Object[])rightRowSetSource.getArray(); + rightRowSetSource.setArray(destState); + final Object [] oldLeftState = leftRowSetSource.getArray(); + final Object [] destLeftState = new Object[tableSize]; + leftRowSetSource.setArray(destLeftState); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final Object currentStateValue = (Object)originalStateArray[sourceBucket]; + if (currentStateValue == EMPTY_RIGHT_STATE) { + continue; + } + final long k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == EMPTY_RIGHT_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftState[destinationTableLocation] = oldLeftState[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherObject.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherObject.java new file mode 100644 index 00000000000..f3761d59b87 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherObject.java @@ -0,0 +1,181 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.staticopen.gen; + +import static io.deephaven.util.compare.ObjectComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.ObjectChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.ObjectChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.RowSetBuilderRandom; +import io.deephaven.engine.rowset.RowSetFactory; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.StaticAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableObjectArraySource; +import java.lang.Object; +import java.lang.Override; +import java.util.Arrays; +import org.apache.commons.lang3.mutable.MutableInt; + +final class StaticAsOfJoinHasherObject extends StaticAsOfJoinStateManagerTypedBase { + private final ImmutableObjectArraySource mainKeySource0; + + public StaticAsOfJoinHasherObject(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableObjectArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final ObjectChunk keyChunk0 = sourceKeyChunks[0].asObjectChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final Object k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + rightRowSetSource.set(tableLocation, RowSetFactory.builderSequential()); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final ObjectChunk keyChunk0 = sourceKeyChunks[0].asObjectChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final Object k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void decorateLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, MutableInt hashSlotOffset, + RowSetBuilderRandom foundBuilder) { + final ObjectChunk keyChunk0 = sourceKeyChunks[0].asObjectChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final Object k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long indexKey = rowKeyChunk.get(chunkPosition); + if (addLeftIndex(tableLocation, indexKey) && hashSlots != null) { + hashSlots.set(hashSlotOffset.getAndIncrement(), (long)tableLocation); + foundBuilder.addKey(indexKey); + } + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + protected void decorateWithRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final ObjectChunk keyChunk0 = sourceKeyChunks[0].asObjectChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final Object k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + private static int hash(Object k0) { + int hash = ObjectChunkHasher.hashInitialSingle(k0); + return hash; + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final Object[] destKeyArray0 = new Object[tableSize]; + final Object[] destState = new Object[tableSize]; + Arrays.fill(destState, EMPTY_RIGHT_STATE); + final Object [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final Object [] originalStateArray = (Object[])rightRowSetSource.getArray(); + rightRowSetSource.setArray(destState); + final Object [] oldLeftState = leftRowSetSource.getArray(); + final Object [] destLeftState = new Object[tableSize]; + leftRowSetSource.setArray(destLeftState); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final Object currentStateValue = (Object)originalStateArray[sourceBucket]; + if (currentStateValue == EMPTY_RIGHT_STATE) { + continue; + } + final Object k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == EMPTY_RIGHT_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftState[destinationTableLocation] = oldLeftState[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherShort.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherShort.java new file mode 100644 index 00000000000..709a4cd161d --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/StaticAsOfJoinHasherShort.java @@ -0,0 +1,181 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.engine.table.impl.by.typed.TypedHasherFactory +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.staticopen.gen; + +import static io.deephaven.util.compare.ShortComparisons.eq; + +import io.deephaven.base.verify.Assert; +import io.deephaven.chunk.Chunk; +import io.deephaven.chunk.LongChunk; +import io.deephaven.chunk.ShortChunk; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.chunk.util.hashing.ShortChunkHasher; +import io.deephaven.engine.rowset.RowSequence; +import io.deephaven.engine.rowset.RowSetBuilderRandom; +import io.deephaven.engine.rowset.RowSetFactory; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.StaticAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.sources.LongArraySource; +import io.deephaven.engine.table.impl.sources.immutable.ImmutableShortArraySource; +import java.lang.Object; +import java.lang.Override; +import java.util.Arrays; +import org.apache.commons.lang3.mutable.MutableInt; + +final class StaticAsOfJoinHasherShort extends StaticAsOfJoinStateManagerTypedBase { + private final ImmutableShortArraySource mainKeySource0; + + public StaticAsOfJoinHasherShort(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + super(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor); + this.mainKeySource0 = (ImmutableShortArraySource) super.mainKeySources[0]; + this.mainKeySource0.ensureCapacity(tableSize); + } + + private int nextTableLocation(int tableLocation) { + return (tableLocation + 1) & (tableSize - 1); + } + + protected void buildFromLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final ShortChunk keyChunk0 = sourceKeyChunks[0].asShortChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final short k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + rightRowSetSource.set(tableLocation, RowSetFactory.builderSequential()); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addLeftIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void buildFromRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final ShortChunk keyChunk0 = sourceKeyChunks[0].asShortChunk(); + final int chunkSize = keyChunk0.size(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final short k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (true) { + Object rightSideSentinel = rightRowSetSource.getUnsafe(tableLocation); + if (rightSideSentinel == EMPTY_RIGHT_STATE) { + numEntries++; + mainKeySource0.set(tableLocation, k0); + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } else { + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + } + + protected void decorateLeftSide(RowSequence rowSequence, Chunk[] sourceKeyChunks, + LongArraySource hashSlots, MutableInt hashSlotOffset, + RowSetBuilderRandom foundBuilder) { + final ShortChunk keyChunk0 = sourceKeyChunks[0].asShortChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final short k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + final long indexKey = rowKeyChunk.get(chunkPosition); + if (addLeftIndex(tableLocation, indexKey) && hashSlots != null) { + hashSlots.set(hashSlotOffset.getAndIncrement(), (long)tableLocation); + foundBuilder.addKey(indexKey); + } + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + protected void decorateWithRightSide(RowSequence rowSequence, Chunk[] sourceKeyChunks) { + final ShortChunk keyChunk0 = sourceKeyChunks[0].asShortChunk(); + final LongChunk rowKeyChunk = rowSequence.asRowKeyChunk(); + final int chunkSize = keyChunk0.size(); + for (int chunkPosition = 0; chunkPosition < chunkSize; ++chunkPosition) { + final short k0 = keyChunk0.get(chunkPosition); + final int hash = hash(k0); + final int firstTableLocation = hashToTableLocation(hash); + int tableLocation = firstTableLocation; + while (rightRowSetSource.getUnsafe(tableLocation) != EMPTY_RIGHT_STATE) { + if (eq(mainKeySource0.getUnsafe(tableLocation), k0)) { + addRightIndex(tableLocation, rowKeyChunk.get(chunkPosition)); + break; + } + tableLocation = nextTableLocation(tableLocation); + Assert.neq(tableLocation, "tableLocation", firstTableLocation, "firstTableLocation"); + } + } + } + + private static int hash(short k0) { + int hash = ShortChunkHasher.hashInitialSingle(k0); + return hash; + } + + @Override + protected void rehashInternalFull(final int oldSize) { + final short[] destKeyArray0 = new short[tableSize]; + final Object[] destState = new Object[tableSize]; + Arrays.fill(destState, EMPTY_RIGHT_STATE); + final short [] originalKeyArray0 = mainKeySource0.getArray(); + mainKeySource0.setArray(destKeyArray0); + final Object [] originalStateArray = (Object[])rightRowSetSource.getArray(); + rightRowSetSource.setArray(destState); + final Object [] oldLeftState = leftRowSetSource.getArray(); + final Object [] destLeftState = new Object[tableSize]; + leftRowSetSource.setArray(destLeftState); + for (int sourceBucket = 0; sourceBucket < oldSize; ++sourceBucket) { + final Object currentStateValue = (Object)originalStateArray[sourceBucket]; + if (currentStateValue == EMPTY_RIGHT_STATE) { + continue; + } + final short k0 = originalKeyArray0[sourceBucket]; + final int hash = hash(k0); + final int firstDestinationTableLocation = hashToTableLocation(hash); + int destinationTableLocation = firstDestinationTableLocation; + while (true) { + if (destState[destinationTableLocation] == EMPTY_RIGHT_STATE) { + destKeyArray0[destinationTableLocation] = k0; + destState[destinationTableLocation] = originalStateArray[sourceBucket]; + destLeftState[destinationTableLocation] = oldLeftState[sourceBucket]; + break; + } + destinationTableLocation = nextTableLocation(destinationTableLocation); + Assert.neq(destinationTableLocation, "destinationTableLocation", firstDestinationTableLocation, "firstDestinationTableLocation"); + } + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/TypedHashDispatcher.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/TypedHashDispatcher.java new file mode 100644 index 00000000000..b00bb546e6c --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/asofjoin/typed/staticopen/gen/TypedHashDispatcher.java @@ -0,0 +1,43 @@ +// DO NOT EDIT THIS CLASS, AUTOMATICALLY GENERATED BY io.deephaven.replicators.ReplicateTypedHashers +// Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.asofjoin.typed.staticopen.gen; + +import io.deephaven.chunk.ChunkType; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.StaticAsOfJoinStateManagerTypedBase; +import java.util.Arrays; + +/** + * The TypedHashDispatcher returns a pre-generated and precompiled hasher instance suitable for the provided column sources, or null if there is not a precompiled hasher suitable for the specified sources. */ +public class TypedHashDispatcher { + private TypedHashDispatcher() { + // static use only + } + + public static StaticAsOfJoinStateManagerTypedBase dispatch(ColumnSource[] tableKeySources, + ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, + double targetLoadFactor) { + final ChunkType[] chunkTypes = Arrays.stream(tableKeySources).map(ColumnSource::getChunkType).toArray(ChunkType[]::new);; + if (chunkTypes.length == 1) { + return dispatchSingle(chunkTypes[0], tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + } + return null; + } + + private static StaticAsOfJoinStateManagerTypedBase dispatchSingle(ChunkType chunkType, + ColumnSource[] tableKeySources, ColumnSource[] originalTableKeySources, int tableSize, + double maximumLoadFactor, double targetLoadFactor) { + switch (chunkType) { + default: throw new UnsupportedOperationException("Invalid chunk type for typed hashers: " + chunkType); + case Char: return new StaticAsOfJoinHasherChar(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Byte: return new StaticAsOfJoinHasherByte(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Short: return new StaticAsOfJoinHasherShort(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Int: return new StaticAsOfJoinHasherInt(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Long: return new StaticAsOfJoinHasherLong(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Float: return new StaticAsOfJoinHasherFloat(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Double: return new StaticAsOfJoinHasherDouble(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Object: return new StaticAsOfJoinHasherObject(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + } + } +} diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/typed/TypedHasherFactory.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/typed/TypedHasherFactory.java index bafeaf66812..c6438dd40a5 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/typed/TypedHasherFactory.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/typed/TypedHasherFactory.java @@ -9,12 +9,14 @@ import io.deephaven.chunk.util.hashing.CharChunkHasher; import io.deephaven.compilertools.CompilerTools; import io.deephaven.configuration.Configuration; -import io.deephaven.engine.rowset.RowSequence; -import io.deephaven.engine.rowset.RowSet; +import io.deephaven.engine.rowset.*; import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; import io.deephaven.engine.rowset.chunkattributes.RowKeys; import io.deephaven.engine.table.ColumnSource; import io.deephaven.engine.table.impl.NaturalJoinModifiedSlotTracker; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.asofjoin.StaticAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.asofjoin.TypedAsOfJoinFactory; import io.deephaven.engine.table.impl.naturaljoin.RightIncrementalNaturalJoinStateManagerTypedBase; import io.deephaven.engine.table.impl.by.*; import io.deephaven.engine.table.impl.naturaljoin.IncrementalNaturalJoinStateManagerTypedBase; @@ -24,6 +26,7 @@ import io.deephaven.engine.table.impl.sources.immutable.*; import io.deephaven.util.QueryConstants; import io.deephaven.util.compare.CharComparisons; +import org.apache.commons.lang3.mutable.MutableInt; import org.jetbrains.annotations.NotNull; import javax.lang.model.element.Modifier; @@ -255,6 +258,68 @@ public static HasherConfig hasherConfigForBase(Class baseClass) { TypedNaturalJoinFactory::incrementalShiftLeftMissing, ParameterSpec.builder(long.class, "shiftDelta").build(), probeContextParam)); + } else if (baseClass.equals(StaticAsOfJoinStateManagerTypedBase.class)) { + builder.classPrefix("StaticAsOfJoinHasher").packageGroup("asofjoin").packageMiddle("staticopen") + .openAddressedAlternate(false) + .stateType(Object.class).mainStateName("rightRowSetSource") + .emptyStateName("EMPTY_RIGHT_STATE") + .includeOriginalSources(true) + .supportRehash(true) + .moveMainFull(TypedAsOfJoinFactory::staticMoveMainFull) + .alwaysMoveMain(true) + .rehashFullSetup(TypedAsOfJoinFactory::staticRehashSetup); + + final TypeName longArraySource = TypeName.get(LongArraySource.class); + final ParameterSpec hashSlots = ParameterSpec.builder(longArraySource, "hashSlots").build(); + final ParameterSpec hashSlotOffset = ParameterSpec.builder(MutableInt.class, "hashSlotOffset").build(); + final ParameterSpec foundBuilder = ParameterSpec.builder(RowSetBuilderRandom.class, "foundBuilder").build(); + + builder.addBuild(new HasherConfig.BuildSpec("buildFromLeftSide", "rightSideSentinel", + true, true, TypedAsOfJoinFactory::staticBuildLeftFound, + TypedAsOfJoinFactory::staticBuildLeftInsert)); + + builder.addProbe(new HasherConfig.ProbeSpec("decorateLeftSide", null, + true, TypedAsOfJoinFactory::staticProbeDecorateLeftFound, + null, hashSlots, hashSlotOffset, foundBuilder)); + + builder.addBuild(new HasherConfig.BuildSpec("buildFromRightSide", "rightSideSentinel", + true, true, TypedAsOfJoinFactory::staticBuildRightFound, + TypedAsOfJoinFactory::staticBuildRightInsert)); + + builder.addProbe(new HasherConfig.ProbeSpec("decorateWithRightSide", null, + true, TypedAsOfJoinFactory::staticProbeDecorateRightFound, null)); + + } else if (baseClass.equals(RightIncrementalAsOfJoinStateManagerTypedBase.class)) { + final TypeName longArraySource = TypeName.get(LongArraySource.class); + final ParameterSpec hashSlots = ParameterSpec.builder(longArraySource, "hashSlots").build(); + final ParameterSpec sequentialBuilders = + ParameterSpec.builder(ObjectArraySource.class, "sequentialBuilders").build(); + + builder.classPrefix("RightIncrementalAsOfJoinHasher").packageGroup("asofjoin") + .packageMiddle("rightincopen") + .openAddressedAlternate(true) + .stateType(byte.class).mainStateName("stateSource") + .overflowOrAlternateStateName("alternateStateSource") + .emptyStateName("ENTRY_EMPTY_STATE") + .includeOriginalSources(true) + .supportRehash(true) + .addExtraPartialRehashParameter(hashSlots) + .moveMainFull(TypedAsOfJoinFactory::rightIncrementalMoveMainFull) + .moveMainAlternate(TypedAsOfJoinFactory::rightIncrementalMoveMainAlternate) + .alwaysMoveMain(true) + .rehashFullSetup(TypedAsOfJoinFactory::rightIncrementalRehashSetup); + + builder.addBuild(new HasherConfig.BuildSpec("buildFromLeftSide", "rowState", + true, true, TypedAsOfJoinFactory::rightIncrementalBuildLeftFound, + TypedAsOfJoinFactory::rightIncrementalBuildLeftInsert, hashSlots, sequentialBuilders)); + + builder.addBuild(new HasherConfig.BuildSpec("buildFromRightSide", "rowState", true, + true, TypedAsOfJoinFactory::rightIncrementalRightFound, + TypedAsOfJoinFactory::rightIncrementalRightInsert, hashSlots, sequentialBuilders)); + + builder.addProbe(new HasherConfig.ProbeSpec("probeRightSide", "rowState", + true, TypedAsOfJoinFactory::rightIncrementalProbeDecorateRightFound, null, hashSlots, + sequentialBuilders)); } else { throw new UnsupportedOperationException("Unknown class to make: " + baseClass); } @@ -347,6 +412,26 @@ public static T make(HasherConfig hasherConfig, ColumnSource[] tableKe if (pregeneratedHasher != null) { return pregeneratedHasher; } + } else if (hasherConfig.baseClass + .equals(StaticAsOfJoinStateManagerTypedBase.class)) { + // noinspection unchecked + T pregeneratedHasher = + (T) io.deephaven.engine.table.impl.asofjoin.typed.staticopen.gen.TypedHashDispatcher + .dispatch(tableKeySources, originalKeySources, tableSize, maximumLoadFactor, + targetLoadFactor); + if (pregeneratedHasher != null) { + return pregeneratedHasher; + } + } else if (hasherConfig.baseClass + .equals(RightIncrementalAsOfJoinStateManagerTypedBase.class)) { + // noinspection unchecked + T pregeneratedHasher = + (T) io.deephaven.engine.table.impl.asofjoin.typed.rightincopen.gen.TypedHashDispatcher + .dispatch(tableKeySources, originalKeySources, tableSize, maximumLoadFactor, + targetLoadFactor); + if (pregeneratedHasher != null) { + return pregeneratedHasher; + } } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/join/BucketedChunkedAjMergedListener.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/join/BucketedChunkedAjMergedListener.java index 45174291740..c43fc65cad7 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/join/BucketedChunkedAjMergedListener.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/join/BucketedChunkedAjMergedListener.java @@ -11,6 +11,7 @@ import io.deephaven.engine.table.MatchPair; import io.deephaven.engine.table.impl.*; import io.deephaven.chunk.util.hashing.ChunkEquals; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalHashedAsOfJoinStateManager; import io.deephaven.engine.table.impl.sort.LongSortKernel; import io.deephaven.engine.table.ColumnSource; import io.deephaven.engine.table.impl.sources.LongArraySource; @@ -51,7 +52,7 @@ public class BucketedChunkedAjMergedListener extends MergedListener { private final boolean disallowExactMatch; private final SsaSsaStamp ssaSsaStamp; private final ChunkSsaStamp chunkSsaStamp; - private final RightIncrementalChunkedAsOfJoinStateManager asOfJoinStateManager; + private final RightIncrementalHashedAsOfJoinStateManager asOfJoinStateManager; private final WritableRowRedirection rowRedirection; private final ModifiedColumnSet leftKeyColumns; private final ModifiedColumnSet rightKeyColumns; @@ -91,7 +92,7 @@ public BucketedChunkedAjMergedListener(JoinListenerRecorder leftRecorder, SortingOrder order, boolean disallowExactMatch, SsaSsaStamp ssaSsaStamp, - JoinControl control, RightIncrementalChunkedAsOfJoinStateManager asOfJoinStateManager, + JoinControl control, RightIncrementalHashedAsOfJoinStateManager asOfJoinStateManager, WritableRowRedirection rowRedirection) { super(Arrays.asList(leftRecorder, rightRecorder), Collections.emptyList(), listenerDescription, result); this.leftRecorder = leftRecorder; diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/naturaljoin/typed/incopen/gen/TypedHashDispatcher.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/naturaljoin/typed/incopen/gen/TypedHashDispatcher.java index 422ea0619b2..c9a5dfff8e1 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/naturaljoin/typed/incopen/gen/TypedHashDispatcher.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/naturaljoin/typed/incopen/gen/TypedHashDispatcher.java @@ -9,9 +9,7 @@ import java.util.Arrays; /** - * The TypedHashDispatcher returns a pre-generated and precompiled hasher instance suitable for the provided column - * sources, or null if there is not a precompiled hasher suitable for the specified sources. - */ + * The TypedHashDispatcher returns a pre-generated and precompiled hasher instance suitable for the provided column sources, or null if there is not a precompiled hasher suitable for the specified sources. */ public class TypedHashDispatcher { private TypedHashDispatcher() { // static use only @@ -20,11 +18,9 @@ private TypedHashDispatcher() { public static IncrementalNaturalJoinStateManagerTypedBase dispatch(ColumnSource[] tableKeySources, ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, double targetLoadFactor) { - final ChunkType[] chunkTypes = - Arrays.stream(tableKeySources).map(ColumnSource::getChunkType).toArray(ChunkType[]::new);; + final ChunkType[] chunkTypes = Arrays.stream(tableKeySources).map(ColumnSource::getChunkType).toArray(ChunkType[]::new);; if (chunkTypes.length == 1) { - return dispatchSingle(chunkTypes[0], tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, - targetLoadFactor); + return dispatchSingle(chunkTypes[0], tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); } return null; } @@ -33,32 +29,15 @@ private static IncrementalNaturalJoinStateManagerTypedBase dispatchSingle(ChunkT ColumnSource[] tableKeySources, ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, double targetLoadFactor) { switch (chunkType) { - default: - throw new UnsupportedOperationException("Invalid chunk type for typed hashers: " + chunkType); - case Char: - return new IncrementalNaturalJoinHasherChar(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Byte: - return new IncrementalNaturalJoinHasherByte(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Short: - return new IncrementalNaturalJoinHasherShort(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Int: - return new IncrementalNaturalJoinHasherInt(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Long: - return new IncrementalNaturalJoinHasherLong(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Float: - return new IncrementalNaturalJoinHasherFloat(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Double: - return new IncrementalNaturalJoinHasherDouble(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Object: - return new IncrementalNaturalJoinHasherObject(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); + default: throw new UnsupportedOperationException("Invalid chunk type for typed hashers: " + chunkType); + case Char: return new IncrementalNaturalJoinHasherChar(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Byte: return new IncrementalNaturalJoinHasherByte(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Short: return new IncrementalNaturalJoinHasherShort(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Int: return new IncrementalNaturalJoinHasherInt(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Long: return new IncrementalNaturalJoinHasherLong(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Float: return new IncrementalNaturalJoinHasherFloat(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Double: return new IncrementalNaturalJoinHasherDouble(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Object: return new IncrementalNaturalJoinHasherObject(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); } } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/naturaljoin/typed/rightincopen/gen/TypedHashDispatcher.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/naturaljoin/typed/rightincopen/gen/TypedHashDispatcher.java index 74c553bbc31..10745e4f390 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/naturaljoin/typed/rightincopen/gen/TypedHashDispatcher.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/naturaljoin/typed/rightincopen/gen/TypedHashDispatcher.java @@ -9,9 +9,7 @@ import java.util.Arrays; /** - * The TypedHashDispatcher returns a pre-generated and precompiled hasher instance suitable for the provided column - * sources, or null if there is not a precompiled hasher suitable for the specified sources. - */ + * The TypedHashDispatcher returns a pre-generated and precompiled hasher instance suitable for the provided column sources, or null if there is not a precompiled hasher suitable for the specified sources. */ public class TypedHashDispatcher { private TypedHashDispatcher() { // static use only @@ -20,11 +18,9 @@ private TypedHashDispatcher() { public static RightIncrementalNaturalJoinStateManagerTypedBase dispatch(ColumnSource[] tableKeySources, ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, double targetLoadFactor) { - final ChunkType[] chunkTypes = - Arrays.stream(tableKeySources).map(ColumnSource::getChunkType).toArray(ChunkType[]::new);; + final ChunkType[] chunkTypes = Arrays.stream(tableKeySources).map(ColumnSource::getChunkType).toArray(ChunkType[]::new);; if (chunkTypes.length == 1) { - return dispatchSingle(chunkTypes[0], tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, - targetLoadFactor); + return dispatchSingle(chunkTypes[0], tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); } return null; } @@ -33,32 +29,15 @@ private static RightIncrementalNaturalJoinStateManagerTypedBase dispatchSingle(C ColumnSource[] tableKeySources, ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, double targetLoadFactor) { switch (chunkType) { - default: - throw new UnsupportedOperationException("Invalid chunk type for typed hashers: " + chunkType); - case Char: - return new RightIncrementalNaturalJoinHasherChar(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Byte: - return new RightIncrementalNaturalJoinHasherByte(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Short: - return new RightIncrementalNaturalJoinHasherShort(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Int: - return new RightIncrementalNaturalJoinHasherInt(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Long: - return new RightIncrementalNaturalJoinHasherLong(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Float: - return new RightIncrementalNaturalJoinHasherFloat(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Double: - return new RightIncrementalNaturalJoinHasherDouble(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Object: - return new RightIncrementalNaturalJoinHasherObject(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); + default: throw new UnsupportedOperationException("Invalid chunk type for typed hashers: " + chunkType); + case Char: return new RightIncrementalNaturalJoinHasherChar(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Byte: return new RightIncrementalNaturalJoinHasherByte(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Short: return new RightIncrementalNaturalJoinHasherShort(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Int: return new RightIncrementalNaturalJoinHasherInt(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Long: return new RightIncrementalNaturalJoinHasherLong(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Float: return new RightIncrementalNaturalJoinHasherFloat(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Double: return new RightIncrementalNaturalJoinHasherDouble(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Object: return new RightIncrementalNaturalJoinHasherObject(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); } } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/naturaljoin/typed/staticopen/gen/TypedHashDispatcher.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/naturaljoin/typed/staticopen/gen/TypedHashDispatcher.java index 2141025a727..72b8b27d19a 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/naturaljoin/typed/staticopen/gen/TypedHashDispatcher.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/naturaljoin/typed/staticopen/gen/TypedHashDispatcher.java @@ -9,9 +9,7 @@ import java.util.Arrays; /** - * The TypedHashDispatcher returns a pre-generated and precompiled hasher instance suitable for the provided column - * sources, or null if there is not a precompiled hasher suitable for the specified sources. - */ + * The TypedHashDispatcher returns a pre-generated and precompiled hasher instance suitable for the provided column sources, or null if there is not a precompiled hasher suitable for the specified sources. */ public class TypedHashDispatcher { private TypedHashDispatcher() { // static use only @@ -20,11 +18,9 @@ private TypedHashDispatcher() { public static StaticNaturalJoinStateManagerTypedBase dispatch(ColumnSource[] tableKeySources, ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, double targetLoadFactor) { - final ChunkType[] chunkTypes = - Arrays.stream(tableKeySources).map(ColumnSource::getChunkType).toArray(ChunkType[]::new);; + final ChunkType[] chunkTypes = Arrays.stream(tableKeySources).map(ColumnSource::getChunkType).toArray(ChunkType[]::new);; if (chunkTypes.length == 1) { - return dispatchSingle(chunkTypes[0], tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, - targetLoadFactor); + return dispatchSingle(chunkTypes[0], tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); } return null; } @@ -33,32 +29,15 @@ private static StaticNaturalJoinStateManagerTypedBase dispatchSingle(ChunkType c ColumnSource[] tableKeySources, ColumnSource[] originalTableKeySources, int tableSize, double maximumLoadFactor, double targetLoadFactor) { switch (chunkType) { - default: - throw new UnsupportedOperationException("Invalid chunk type for typed hashers: " + chunkType); - case Char: - return new StaticNaturalJoinHasherChar(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Byte: - return new StaticNaturalJoinHasherByte(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Short: - return new StaticNaturalJoinHasherShort(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Int: - return new StaticNaturalJoinHasherInt(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Long: - return new StaticNaturalJoinHasherLong(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Float: - return new StaticNaturalJoinHasherFloat(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Double: - return new StaticNaturalJoinHasherDouble(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); - case Object: - return new StaticNaturalJoinHasherObject(tableKeySources, originalTableKeySources, tableSize, - maximumLoadFactor, targetLoadFactor); + default: throw new UnsupportedOperationException("Invalid chunk type for typed hashers: " + chunkType); + case Char: return new StaticNaturalJoinHasherChar(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Byte: return new StaticNaturalJoinHasherByte(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Short: return new StaticNaturalJoinHasherShort(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Int: return new StaticNaturalJoinHasherInt(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Long: return new StaticNaturalJoinHasherLong(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Float: return new StaticNaturalJoinHasherFloat(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Double: return new StaticNaturalJoinHasherDouble(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); + case Object: return new StaticNaturalJoinHasherObject(tableKeySources, originalTableKeySources, tableSize, maximumLoadFactor, targetLoadFactor); } } } diff --git a/engine/table/src/test/java/io/deephaven/engine/table/impl/QueryTableAjTest.java b/engine/table/src/test/java/io/deephaven/engine/table/impl/QueryTableAjTest.java index 694e5ca09b7..8d3ff7e059d 100644 --- a/engine/table/src/test/java/io/deephaven/engine/table/impl/QueryTableAjTest.java +++ b/engine/table/src/test/java/io/deephaven/engine/table/impl/QueryTableAjTest.java @@ -763,7 +763,22 @@ int tableSizeForLeftBuild(Table leftTable) { @Override double getMaximumLoadFactor() { - return 20.0; + if (AsOfJoinHelper.USE_TYPED_STATE_MANAGER) { + // allow this test to function for OA + return 0.75; + } else { + return 20.0; + } + } + + @Override + int initialBuildSize() { + if (AsOfJoinHelper.USE_TYPED_STATE_MANAGER) { + // allow this test to function for OA + return 1 << 3; + } else { + return super.initialBuildSize(); + } } @Override diff --git a/replication/reflective/src/main/java/io/deephaven/replicators/ReplicateTypedHashers.java b/replication/reflective/src/main/java/io/deephaven/replicators/ReplicateTypedHashers.java index c00b776de62..65da149eece 100644 --- a/replication/reflective/src/main/java/io/deephaven/replicators/ReplicateTypedHashers.java +++ b/replication/reflective/src/main/java/io/deephaven/replicators/ReplicateTypedHashers.java @@ -6,6 +6,8 @@ import com.squareup.javapoet.TypeSpec; import io.deephaven.chunk.ChunkType; import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.asofjoin.RightIncrementalAsOfJoinStateManagerTypedBase; +import io.deephaven.engine.table.impl.asofjoin.StaticAsOfJoinStateManagerTypedBase; import io.deephaven.engine.table.impl.naturaljoin.RightIncrementalNaturalJoinStateManagerTypedBase; import io.deephaven.engine.table.impl.by.IncrementalChunkedOperatorAggregationStateManagerOpenAddressedBase; import io.deephaven.engine.table.impl.by.IncrementalChunkedOperatorAggregationStateManagerTypedBase; @@ -31,6 +33,8 @@ public static void main(String[] args) throws IOException { generatePackage(StaticNaturalJoinStateManagerTypedBase.class, false); generatePackage(RightIncrementalNaturalJoinStateManagerTypedBase.class, false); generatePackage(IncrementalNaturalJoinStateManagerTypedBase.class, false); + generatePackage(StaticAsOfJoinStateManagerTypedBase.class, false); + generatePackage(RightIncrementalAsOfJoinStateManagerTypedBase.class, false); } private static void generatePackage(Class baseClass, boolean doDouble) throws IOException {