Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for (start<0 & stop>0) in slice #4076

Merged
merged 5 commits into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions engine/api/src/main/java/io/deephaven/engine/table/Table.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,14 @@ public interface Table extends
String UNIQUE_KEYS_ATTRIBUTE = "uniqueKeys";
String FILTERABLE_COLUMNS_ATTRIBUTE = "FilterableColumns";
String TOTALS_TABLE_ATTRIBUTE = "TotalsTable";
/**
* If this attribute is set, we can only add new row keys, we can never shift them, modify them, or remove them.
*/
String ADD_ONLY_TABLE_ATTRIBUTE = "AddOnly";
/**
* If this attribute is set, we can only append new row keys to the end of the table. We can never shift them,
* modify them, or remove them.
*/
String APPEND_ONLY_TABLE_ATTRIBUTE = "AppendOnly";
String TEST_SOURCE_TABLE_ATTRIBUTE = "TestSource";
/**
Expand Down Expand Up @@ -355,6 +362,11 @@ public interface Table extends
* <p>
* If the firstPosition is negative and the lastPosition is negative, they are both counted from the end of the
* table. For example, slice(-2, -1) returns the second to last row of the table.
* <p>
* If firstPosition is negative and lastPosition is positive, then firstPosition is counted from the end of the
* table, inclusively. The lastPosition is counted from the beginning of the table, exclusively. For example,
* slice(-3, 5) returns all rows starting from the third-last row to the fifth row of the table. If there are no
* rows between these positions, the function will return an empty table.
*
* @param firstPositionInclusive the first position to include in the result
* @param lastPositionExclusive the last position to include in the result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ public class SliceLikeOperation implements QueryTable.Operation<QueryTable> {
public static SliceLikeOperation slice(final QueryTable parent, final long firstPositionInclusive,
final long lastPositionExclusive, final String op) {

if (firstPositionInclusive < 0 && lastPositionExclusive > 0) {
throw new IllegalArgumentException("Can not slice with a negative first position (" + firstPositionInclusive
+ ") and positive last position (" + lastPositionExclusive + ")");
}
// note: first >= 0 && last < 0 is allowed, otherwise first must be less than last
if ((firstPositionInclusive < 0 || lastPositionExclusive >= 0)
&& lastPositionExclusive < firstPositionInclusive) {
Expand Down Expand Up @@ -102,15 +98,19 @@ public Result<QueryTable> initialize(boolean usePrev, long beforeClock) {
}

if (operation.equals("headPct")) {
// headPct has a floating tail, so we can only propagate if append-only
// With headPct, resultTable has a floating tail. So if parent is ADD_ONLY, new rows might be added and old
// rows removed from resultTable as the parent grows. But if parent is APPEND_ONLY, new rows can only be
// appended to resultTable
if (parent.isAppendOnly()) {
resultTable.setAttribute(Table.ADD_ONLY_TABLE_ATTRIBUTE, true);
resultTable.setAttribute(Table.APPEND_ONLY_TABLE_ATTRIBUTE, true);
}
} else if (!operation.equals("tailPct") && getFirstPositionInclusive() >= 0) {
// tailPct has a floating head, so we can't propagate either property
// otherwise, if the first row is fixed (not negative), then we can propagate add-only/append-only
if (parent.isAddOnly()) {
// With tailPct or when first position is negative, even if the parent is APPEND_ONLY, new rows can be added
// and old rows removed from resultTable as the parent grows. Therefore, we cannot propagate the property.
// Otherwise, we can propagate APPEND_ONLY and conditionally propagate ADD_ONLY.
if (parent.isAddOnly() && getLastPositionExclusive() <= 0) {
// The tail cannot be fixed, else we might need to remove rows
resultTable.setAttribute(Table.ADD_ONLY_TABLE_ATTRIBUTE, true);
}
if (parent.isAppendOnly()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,21 +355,27 @@ public Table e() {
}
}

public void testTailWithGrowth() {
public void testGrowthAppendUpdatePattern() {
final long steps = 4096;

for (int j = 1; j < 100; j += 7) {
final QueryTable upTable = getTable(true, 0, new Random(0), new ColumnInfo[0]);
upTable.setAttribute(Table.ADD_ONLY_TABLE_ATTRIBUTE, true);
upTable.setAttribute(Table.APPEND_ONLY_TABLE_ATTRIBUTE, true);
final QueryTable queryTable = (QueryTable) upTable.updateView("I=i", "II=ii");
final EvalNugget[] en = {
EvalNugget.from(() -> queryTable.slice(-35, 0))
EvalNugget.from(() -> queryTable.slice(10, 15)),
EvalNugget.from(() -> queryTable.slice(10, -15)),
EvalNugget.from(() -> queryTable.slice(-35, 0)),
EvalNugget.from(() -> queryTable.slice(-15, 10))
};

for (int i = 0; i < steps; ++i) {
final long ii = i;
final long jj = j;
final ControlledUpdateGraph updateGraph = ExecutionContext.getContext().getUpdateGraph().cast();
updateGraph.runWithinUnitTestCycle(() -> {
// Appending the rows at the end
RowSet added1 = RowSetFactory.fromRange(ii * jj, (ii + 1) * jj - 1);
upTable.getRowSet().writableCast().insert(added1);
TableUpdate update =
Expand All @@ -383,6 +389,68 @@ public void testTailWithGrowth() {
}
}

public void testGrowthPrependUpdatePattern() {
final int numRowsToAdd = 10;
final int tableSize = 50;
final int steps = (tableSize / numRowsToAdd);

final QueryTable upTable = getTable(true, 0, new Random(0), new ColumnInfo[0]);
upTable.setAttribute(Table.ADD_ONLY_TABLE_ATTRIBUTE, true);
final QueryTable queryTable = (QueryTable) upTable.updateView("K=k");
final EvalNugget[] en = {
EvalNugget.from(() -> queryTable.slice(10, 15)),
EvalNugget.from(() -> queryTable.slice(10, -15)),
EvalNugget.from(() -> queryTable.slice(-35, 0)),
EvalNugget.from(() -> queryTable.slice(-15, 10))
};

for (int i = steps; i > 0; --i) {
final long ii = i;
final ControlledUpdateGraph updateGraph = ExecutionContext.getContext().getUpdateGraph().cast();
// Prepending 10 rows at time, starting from (40, 49), (30, 39)...
updateGraph.runWithinUnitTestCycle(() -> {
RowSet added1 = RowSetFactory.fromRange((ii - 1) * numRowsToAdd, ((ii) * numRowsToAdd) - 1);
upTable.getRowSet().writableCast().insert(added1);
TableUpdate update =
new TableUpdateImpl(added1, RowSetFactory.empty(),
RowSetFactory.empty(), RowSetShiftData.EMPTY, ModifiedColumnSet.EMPTY);
upTable.notifyListeners(update);
});

TstUtils.validate("", en);
}
}


public void testShrinkageUpdatePattern() {
final int numRowsToDelete = 10;
final int tableSize = 50;
final int steps = (tableSize / numRowsToDelete);
final QueryTable upTable = TstUtils.testRefreshingTable(RowSetFactory.fromRange(0, tableSize - 1).toTracking());
final QueryTable queryTable = (QueryTable) upTable.updateView("K=k");
final EvalNugget[] en = {
EvalNugget.from(() -> queryTable.slice(10, 15)),
EvalNugget.from(() -> queryTable.slice(10, -15)),
EvalNugget.from(() -> queryTable.slice(-35, 0)),
EvalNugget.from(() -> queryTable.slice(-15, 10))
};

for (int i = 0; i < steps; ++i) {
final long ii = i;
final ControlledUpdateGraph updateGraph = ExecutionContext.getContext().getUpdateGraph().cast();
updateGraph.runWithinUnitTestCycle(() -> {
RowSet removed1 = RowSetFactory.fromRange(ii * numRowsToDelete, ((ii + 1) * numRowsToDelete) - 1);
upTable.getRowSet().writableCast().remove(removed1);
TableUpdate update =
new TableUpdateImpl(RowSetFactory.empty(), removed1,
RowSetFactory.empty(), RowSetShiftData.EMPTY, ModifiedColumnSet.EMPTY);
upTable.notifyListeners(update);
});

TstUtils.validate("", en);
}
}

public void testLongTail() {
final Table bigTable = emptyTable(2 * (long) (Integer.MAX_VALUE)).updateView("I=i", "II=ii");
final Table tailed = bigTable.tail(1);
Expand Down Expand Up @@ -420,6 +488,8 @@ public void testSlice() {
doSliceTest(table, "bcdefghijklmnopqrstuvwxy", 1, -1);
doSliceTest(table, "", 2, 2);
doSliceTest(table, "c", 2, 3);
doSliceTest(table, "wxy", -4, 25);
doSliceTest(table, "", -4, 20);
}

private void doSliceTest(QueryTable table, String expected, int firstPositionInclusive, int lastPositionExclusive) {
Expand Down