Skip to content

HBASE-28626 MultiRowRangeFilter deserialization fails in org.apache.h… #5951

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

Merged
merged 5 commits into from
May 30, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.Objects;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
Expand Down Expand Up @@ -203,6 +205,79 @@ public ByteArrayComparable build() {

}

/**
* This DTO omits the pseudo-getters in MultiRowRangeFilter.RowRange which break Jackson
* deserialization. It also avoids adding those as dummy JSON elements.
*/
static class RowRangeModel {

protected byte[] startRow;

protected boolean startRowInclusive = true;

protected byte[] stopRow;

protected boolean stopRowInclusive = false;

public RowRangeModel() {
}

public RowRangeModel(MultiRowRangeFilter.RowRange rr) {
this.startRow = rr.getStartRow();
this.startRowInclusive = rr.isStartRowInclusive();
this.stopRow = rr.getStopRow();
this.stopRowInclusive = rr.isStopRowInclusive();
}

public MultiRowRangeFilter.RowRange build() {
return new MultiRowRangeFilter.RowRange(startRow, startRowInclusive, stopRow,
stopRowInclusive);
}

public byte[] getStartRow() {
return startRow;
}

public byte[] getStopRow() {
return stopRow;
}

/** Returns if start row is inclusive. */
public boolean isStartRowInclusive() {
return startRowInclusive;
}

/** Returns if stop row is inclusive. */
public boolean isStopRowInclusive() {
return stopRowInclusive;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(startRow);
result = prime * result + Arrays.hashCode(stopRow);
result = prime * result + Objects.hash(startRowInclusive, stopRowInclusive);
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof RowRangeModel)) {
return false;
}
RowRangeModel other = (RowRangeModel) obj;
return Arrays.equals(startRow, other.startRow)
&& startRowInclusive == other.startRowInclusive && Arrays.equals(stopRow, other.stopRow)
&& stopRowInclusive == other.stopRowInclusive;
}

}

// A grab bag of fields, would have been a union if this were C.
// These are null by default and will only be serialized if set (non null).
@XmlAttribute
Expand Down Expand Up @@ -242,7 +317,7 @@ public ByteArrayComparable build() {
@XmlElement
public List<String> prefixes;
@XmlElement
private List<RowRange> ranges;
private List<RowRangeModel> ranges;
@XmlElement
public List<Long> timestamps;

Expand Down Expand Up @@ -333,8 +408,7 @@ public FilterModel(Filter filter) {
case MultiRowRangeFilter:
this.ranges = new ArrayList<>();
for (RowRange range : ((MultiRowRangeFilter) filter).getRowRanges()) {
this.ranges.add(new RowRange(range.getStartRow(), range.isStartRowInclusive(),
range.getStopRow(), range.isStopRowInclusive()));
this.ranges.add(new RowRangeModel(range));
}
break;
case PageFilter:
Expand Down Expand Up @@ -438,7 +512,11 @@ public Filter build() {
}
break;
case MultiRowRangeFilter: {
filter = new MultiRowRangeFilter(ranges);
ArrayList<MultiRowRangeFilter.RowRange> rowRanges = new ArrayList<>(ranges.size());
for (RowRangeModel rangeModel : ranges) {
rowRanges.add(rangeModel.build());
}
filter = new MultiRowRangeFilter(rowRanges);
}
break;
case PageFilter:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import org.apache.hadoop.hbase.filter.FilterList.Operator;
import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
import org.apache.hadoop.hbase.filter.InclusiveStopFilter;
import org.apache.hadoop.hbase.filter.MultiRowRangeFilter;
import org.apache.hadoop.hbase.filter.PageFilter;
import org.apache.hadoop.hbase.filter.PrefixFilter;
import org.apache.hadoop.hbase.filter.QualifierFilter;
Expand Down Expand Up @@ -963,4 +964,18 @@ public void testFirstKeyOnlyFilter() throws Exception {
new KeyValue(ROWS_TWO[3], FAMILIES[0], QUALIFIERS_TWO[0], VALUES[1]) };
verifyScanFull(s, kvs);
}

@Test
public void testMultiRowRangeFilter() throws Exception {
long expectedRows = 2;
long expectedKeys = colsPerRow;
List<MultiRowRangeFilter.RowRange> ranges = new ArrayList<>();
// Both return only the third element, as the second one is deleted during initialization.
ranges.add(new MultiRowRangeFilter.RowRange(ROWS_ONE[1], true, ROWS_ONE[2], true));
ranges.add(new MultiRowRangeFilter.RowRange(ROWS_TWO[0], false, ROWS_TWO[3], false));

Scan s = new Scan();
s.setFilter(new MultiRowRangeFilter(ranges));
verifyScan(s, expectedRows, expectedKeys);
}
}