Skip to content

Commit 6abae78

Browse files
committed
Resolves #1076: [bug] Continuation unused in scanIndex with EndpointType.PREFIX_STRING
1 parent bad6717 commit 6abae78

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.apple.foundationdb.record.cursors.BaseCursor;
4141
import com.apple.foundationdb.record.cursors.CursorLimitManager;
4242
import com.apple.foundationdb.subspace.Subspace;
43+
import com.apple.foundationdb.tuple.ByteArrayUtil;
4344
import com.apple.foundationdb.tuple.Tuple;
4445
import com.google.protobuf.ByteString;
4546
import com.google.protobuf.ZeroCopyByteString;
@@ -246,6 +247,11 @@ protected void prepare() {
246247
// left (inclusive) and another on the right (exclusive).
247248
prefixLength = calculatePrefixLength();
248249

250+
// When both endpoints are prefix strings, we should strip off the last byte \x00 from Tuple
251+
if (lowEndpoint == EndpointType.PREFIX_STRING && highEndpoint == EndpointType.PREFIX_STRING) {
252+
prefixLength--;
253+
}
254+
249255
reverse = scanProperties.isReverse();
250256
if (continuation != null) {
251257
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: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,81 @@ 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+
System.out.println(kv);
226+
assertArrayEquals(subspace.pack(Tuple.from("apple", j)), kv.getKey());
227+
assertArrayEquals(Tuple.from("apple", j).pack(), kv.getValue());
228+
}
229+
assertThat(cursor.getNext().hasNext(), is(false));
230+
231+
cursor = KeyValueCursor.Builder.withSubspace(subspace)
232+
.setContext(context)
233+
.setRange(range)
234+
.setContinuation(null)
235+
.setScanProperties(new ScanProperties(ExecuteProperties.newBuilder().setReturnedRowLimit(2).build()))
236+
.build();
237+
for (int j = 0; j < 2; j++) {
238+
KeyValue kv = cursor.getNext().get();
239+
System.out.println(kv);
240+
assertArrayEquals(subspace.pack(Tuple.from("apple", j)), kv.getKey());
241+
assertArrayEquals(Tuple.from("apple", j).pack(), kv.getValue());
242+
}
243+
244+
cursor = KeyValueCursor.Builder.withSubspace(subspace)
245+
.setContext(context)
246+
.setRange(range)
247+
.setContinuation(cursor.getNext().getContinuation().toBytes())
248+
.setScanProperties(new ScanProperties(ExecuteProperties.newBuilder().setReturnedRowLimit(2).build()))
249+
.build();
250+
251+
for (int j = 2; j < 4; j++) {
252+
KeyValue kv = cursor.getNext().get();
253+
System.out.println(kv);
254+
assertArrayEquals(subspace.pack(Tuple.from("apple", j)), kv.getKey());
255+
assertArrayEquals(Tuple.from("apple", j).pack(), kv.getValue());
256+
}
257+
258+
cursor = KeyValueCursor.Builder.withSubspace(subspace)
259+
.setContext(context)
260+
.setRange(range)
261+
.setContinuation(cursor.getNext().getContinuation().toBytes())
262+
.setScanProperties(new ScanProperties(ExecuteProperties.newBuilder().setReturnedRowLimit(1).build()))
263+
.build();
264+
265+
for (int j = 4; j < 5; j++) {
266+
KeyValue kv = cursor.getNext().get();
267+
System.out.println(kv);
268+
assertArrayEquals(subspace.pack(Tuple.from("apple", j)), kv.getKey());
269+
assertArrayEquals(Tuple.from("apple", j).pack(), kv.getValue());
270+
}
271+
272+
return null;
273+
});
274+
}
275+
201276
@Test
202277
public void exclusiveRange() {
203278
fdb.run(context -> {

0 commit comments

Comments
 (0)