...
Provide an implementation of the Query interface, introduced in KIP-796: Interactive Query v2 , to support reverseRange and reverseAll
Proposed Changes
The ReverseRangeQuery
class will be used for both reverseRange and reverseAll queries. A reverseAll is performed when no lower and no upper bound is specified. A reverseRange query retrieves a set of keys, specified using an upper and/or lower bound, from the underlying KV store. A reverseAll, on the other hand, retrieves all keys contained in the KV store.
To achieve reverseRange and reverseAll, we can generate a new class like below, we can also reuse lots of code from rangeQuery, to simplify the code we choose reuse the RangeQuery Code.
Code Block | ||||
---|---|---|---|---|
| ||||
@Evolving
public final class ReverseRangeQuery<K, V> implements Query<KeyValueIterator<K, V>> {
private final Optional<K> lower;
private final Optional<K> upper;
private ReverseRangeQuery(final Optional<K> lower, final Optional<K> upper) {
this.lower = lower;
this.upper = upper;
}
/**
* Interactive range query using a lower and upper bound to filter the keys returned.
* @param lower The key that specifies the lower bound of the range
* @param upper The key that specifies the upper bound of the range
* @param <K> The key type
* @param <V> The value type
*/
public static <K, V> ReverseRangeQuery<K, V> withRange(final K lower, final K upper) {
return new ReverseRangeQuery<>(Optional.ofNullable(lower), Optional.ofNullable(upper));
}
/**
* Interactive range query using an upper bound to filter the keys returned.
* If both <K,V> are null, RangQuery returns a full range scan.
* @param upper The key that specifies the upper bound of the range
* @param <K> The key type
* @param <V> The value type
*/
public static <K, V> ReverseRangeQuery<K, V> withUpperBound(final K upper) {
return new ReverseRangeQuery<>(Optional.empty(), Optional.of(upper));
}
/**
* Interactive range query using a lower bound to filter the keys returned.
* @param lower The key that specifies the lower bound of the range
* @param <K> The key type
* @param <V> The value type
*/
public static <K, V> ReverseRangeQuery<K, V> withLowerBound(final K lower) {
return new ReverseRangeQuery<>(Optional.of(lower), Optional.empty());
}
/**
* Interactive scan query that returns all records in the store.
* @param <K> The key type
* @param <V> The value type
*/
public static <K, V> ReverseRangeQuery<K, V> withNoBounds() {
return new ReverseRangeQuery<>(Optional.empty(), Optional.empty());
}
/**
* The lower bound of the query, if specified.
*/
public Optional<K> getLowerBound() {
return lower;
}
/**
* The upper bound of the query, if specified
*/
public Optional<K> getUpperBound() {
return upper;
}
}
|
we add a variable reverse in RangeQuery, the fault value is false, we want do reverseQuery or reverseAll, we can set it to true.
so we generate two public method, the first one is isReverse(), if return true, do reverseQuery otherwise do rangeQuery
the second method is setReverse(), if we want the query do reverseQuery, we can use this method set the reverse to true, so this RangeQuery Stand for ReverseRangeQuery.
Code Block | ||||
---|---|---|---|---|
| ||||
/**
* Interactive query for issuing range queries and scans over KeyValue stores.
* <p>
* A range query retrieves a set of records, specified using an upper and/or lower bound on the keys.
* <p>
* A scan query retrieves all records contained in the store.
* <p>
* If the reverse is false, do RangeQuery. If the reverse is true do ReverseRangeQuery
*/
| ||||
Code Block | ||||
| ||||
@Evolving public final class ReverseRangeQuery<KRangeQuery<K, V> implements Query<KeyValueIterator<K, V>> { private final Optional<K> lower; private final Optional<K> upper; private ReverseRangeQueryboolean reverse; private RangeQuery(final Optional<K> lower, final Optional<K> upper) { this.lower = lower; this.upper = upper; } /** * Interactive range query using a lower and upper bound to filter the keys returned. * @param lower The key that specifies the lower bound of the range * @param upper The key that specifies the upper bound of the range * @param <K> The key type * @param <V> The value type */ public static <K, V> ReverseRangeQuery<KRangeQuery<K, V> withRange(final K lower, final K upper) { return new ReverseRangeQuery<>RangeQuery<>(Optional.ofNullable(lower), Optional.ofNullable(upper)); } /** * Check whether the Query is ReverseRangeQuery. */ public boolean isReverse() { return reverse; } /** * Set the Query to ReverseRangeQuery. */ public void setReverse() { this.reverse = true; } /** * Interactive range query using an upper bound to filter the keys returned. * If both <K,V> are null, RangQuery returns a full range scan. * @param upper The key that specifies the upper bound of the range * @param <K> The key type * @param <V> The value type */ public static <K, V> ReverseRangeQuery<KRangeQuery<K, V> withUpperBound(final K upper) { return new ReverseRangeQuery<>RangeQuery<>(Optional.empty(), Optional.of(upper)); } /** * Interactive range query using a lower bound to filter the keys returned. * @param lower The key that specifies the lower bound of the range * @param <K> The key type * @param <V> The value type */ public static <K, V> ReverseRangeQuery<KRangeQuery<K, V> withLowerBound(final K lower) { return new ReverseRangeQuery<>RangeQuery<>(Optional.of(lower), Optional.empty()); } /** * Interactive scan query that returns all records in the store. * @param <K> The key type * @param <V> The value type */ public static <K, V> ReverseRangeQuery<KRangeQuery<K, V> withNoBounds() { return new ReverseRangeQuery<>RangeQuery<>(Optional.empty(), Optional.empty()); } /** * The lower bound of the query, if specified. */ public Optional<K> getLowerBound() { return lower; } /** * The upper bound of the query, if specified */ public Optional<K> getUpperBound() { return upper; } } |
Test Plan
Because this time we want to achieve reverseRange and reverseAll, if we want to better know whether the reverseRange and reverseAll result is correct or not, we have to do some change in
IQv2StoreIntegrationTest. At before, we store the query result in a set, set cannot tell us the order of the result, so I use the list to store the query result, so we can know the different between the rangeQuery and reverseRangeQuery.
Compatibility, Deprecation, and Migration Plan
...