Skip to content

Commit 36a3f4a

Browse files
committed
Resolves #1076: [bug] Continuation unused in scanIndex with EndpointType.PREFIX_STRING
1 parent ee1d0d8 commit 36a3f4a

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/provider/foundationdb/KeyValueCursorBase.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,11 @@ protected void prepare() {
246246
// left (inclusive) and another on the right (exclusive).
247247
prefixLength = calculatePrefixLength();
248248

249+
// When both endpoints are prefix strings, we should strip off the last byte \x00 from Tuple
250+
if (lowEndpoint == EndpointType.PREFIX_STRING && highEndpoint == EndpointType.PREFIX_STRING) {
251+
prefixLength--;
252+
}
253+
249254
reverse = scanProperties.isReverse();
250255
if (continuation != null) {
251256
final byte[] continuationBytes = new byte[prefixLength + continuation.length];

fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/KeyValueCursorTest.java

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,77 @@ public void inclusiveRange() {
198198
});
199199
}
200200

201+
@Test
202+
public void prefixString() {
203+
fdb.run(context -> {
204+
fdb.database().run(tr -> {
205+
for (int i = 0; i < 5; i++) {
206+
tr.set(subspace.pack(Tuple.from("apple", i)), Tuple.from("apple", i).pack());
207+
}
208+
return null;
209+
});
210+
TupleRange range = new TupleRange(
211+
Tuple.from("a"),
212+
Tuple.from("a"),
213+
EndpointType.PREFIX_STRING,
214+
EndpointType.PREFIX_STRING
215+
);
216+
217+
KeyValueCursor cursor = KeyValueCursor.Builder.withSubspace(subspace)
218+
.setContext(context)
219+
.setRange(range)
220+
.setContinuation(null)
221+
.setScanProperties(ScanProperties.FORWARD_SCAN)
222+
.build();
223+
for (int j = 0; j < 5; j++) {
224+
KeyValue kv = cursor.getNext().get();
225+
assertArrayEquals(subspace.pack(Tuple.from("apple", j)), kv.getKey());
226+
assertArrayEquals(Tuple.from("apple", j).pack(), kv.getValue());
227+
}
228+
assertThat(cursor.getNext().hasNext(), is(false));
229+
230+
cursor = KeyValueCursor.Builder.withSubspace(subspace)
231+
.setContext(context)
232+
.setRange(range)
233+
.setContinuation(null)
234+
.setScanProperties(new ScanProperties(ExecuteProperties.newBuilder().setReturnedRowLimit(2).build()))
235+
.build();
236+
for (int j = 0; j < 2; j++) {
237+
KeyValue kv = cursor.getNext().get();
238+
assertArrayEquals(subspace.pack(Tuple.from("apple", j)), kv.getKey());
239+
assertArrayEquals(Tuple.from("apple", j).pack(), kv.getValue());
240+
}
241+
242+
cursor = KeyValueCursor.Builder.withSubspace(subspace)
243+
.setContext(context)
244+
.setRange(range)
245+
.setContinuation(cursor.getNext().getContinuation().toBytes())
246+
.setScanProperties(new ScanProperties(ExecuteProperties.newBuilder().setReturnedRowLimit(2).build()))
247+
.build();
248+
249+
for (int j = 2; j < 4; j++) {
250+
KeyValue kv = cursor.getNext().get();
251+
assertArrayEquals(subspace.pack(Tuple.from("apple", j)), kv.getKey());
252+
assertArrayEquals(Tuple.from("apple", j).pack(), kv.getValue());
253+
}
254+
255+
cursor = KeyValueCursor.Builder.withSubspace(subspace)
256+
.setContext(context)
257+
.setRange(range)
258+
.setContinuation(cursor.getNext().getContinuation().toBytes())
259+
.setScanProperties(new ScanProperties(ExecuteProperties.newBuilder().setReturnedRowLimit(1).build()))
260+
.build();
261+
262+
for (int j = 4; j < 5; j++) {
263+
KeyValue kv = cursor.getNext().get();
264+
assertArrayEquals(subspace.pack(Tuple.from("apple", j)), kv.getKey());
265+
assertArrayEquals(Tuple.from("apple", j).pack(), kv.getValue());
266+
}
267+
268+
return null;
269+
});
270+
}
271+
201272
@Test
202273
public void exclusiveRange() {
203274
fdb.run(context -> {

0 commit comments

Comments
 (0)