mirror of https://github.com/tikv/client-java.git
				
				
				
			fix scan exception when the start key is empty (lower_bound) (#199)
Signed-off-by: birdstorm <samuelwyf@hotmail.com>
This commit is contained in:
		
							parent
							
								
									4a401776d1
								
							
						
					
					
						commit
						c6d7f0478c
					
				|  | @ -78,26 +78,22 @@ public class RawScanIterator extends ScanIterator { | |||
|       endOfScan = true; | ||||
|       return false; | ||||
|     } | ||||
|     // continue when cache is empty but not null | ||||
|     while (currentCache != null && currentCache.isEmpty()) { | ||||
|       if (cacheLoadFails()) { | ||||
|         return false; | ||||
|       } | ||||
|     } | ||||
|     return notEndOfScan(); | ||||
|   } | ||||
| 
 | ||||
|   private Kvrpcpb.KvPair getCurrent() { | ||||
|     if (isCacheDrained()) { | ||||
|       return null; | ||||
|     } | ||||
|     --limit; | ||||
|     return currentCache.get(index++); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public Kvrpcpb.KvPair next() { | ||||
|     Kvrpcpb.KvPair kv; | ||||
|     // continue when cache is empty but not null | ||||
|     for (kv = getCurrent(); currentCache != null && kv == null; kv = getCurrent()) { | ||||
|       if (cacheLoadFails()) { | ||||
|         return null; | ||||
|       } | ||||
|     } | ||||
|     return kv; | ||||
|     return getCurrent(); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -50,11 +50,8 @@ public abstract class ScanIterator implements Iterator<Kvrpcpb.KvPair> { | |||
|       int limit, | ||||
|       boolean keyOnly) { | ||||
|     this.startKey = requireNonNull(startKey, "start key is null"); | ||||
|     if (startKey.isEmpty()) { | ||||
|       throw new IllegalArgumentException("start key cannot be empty"); | ||||
|     } | ||||
|     this.endKey = Key.toRawKey(requireNonNull(endKey, "end key is null")); | ||||
|     this.hasEndKey = !endKey.equals(ByteString.EMPTY); | ||||
|     this.hasEndKey = !endKey.isEmpty(); | ||||
|     this.limit = limit; | ||||
|     this.keyOnly = keyOnly; | ||||
|     this.conf = conf; | ||||
|  | @ -74,7 +71,7 @@ public abstract class ScanIterator implements Iterator<Kvrpcpb.KvPair> { | |||
|     if (endOfScan || processingLastBatch) { | ||||
|       return true; | ||||
|     } | ||||
|     if (startKey == null || startKey.isEmpty()) { | ||||
|     if (startKey == null) { | ||||
|       return true; | ||||
|     } | ||||
|     try { | ||||
|  | @ -107,7 +104,8 @@ public abstract class ScanIterator implements Iterator<Kvrpcpb.KvPair> { | |||
|         startKey = lastKey.next().toByteString(); | ||||
|       } | ||||
|       // notify last batch if lastKey is greater than or equal to endKey | ||||
|       if (hasEndKey && lastKey.compareTo(endKey) >= 0) { | ||||
|       // if startKey is empty, it indicates +∞ | ||||
|       if (hasEndKey && lastKey.compareTo(endKey) >= 0 || startKey.isEmpty()) { | ||||
|         processingLastBatch = true; | ||||
|         startKey = null; | ||||
|       } | ||||
|  |  | |||
|  | @ -853,7 +853,9 @@ public class RawKVClient implements AutoCloseable { | |||
|   private List<TiRegion> fetchRegionsFromRange( | ||||
|       BackOffer backOffer, ByteString startKey, ByteString endKey) { | ||||
|     List<TiRegion> regions = new ArrayList<>(); | ||||
|     while (startKey.isEmpty() || Key.toRawKey(startKey).compareTo(Key.toRawKey(endKey)) < 0) { | ||||
|     while (startKey.isEmpty() | ||||
|         || endKey.isEmpty() | ||||
|         || Key.toRawKey(startKey).compareTo(Key.toRawKey(endKey)) < 0) { | ||||
|       TiRegion currentRegion = clientBuilder.getRegionManager().getRegionByKey(startKey, backOffer); | ||||
|       regions.add(currentRegion); | ||||
|       startKey = currentRegion.getEndKey(); | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| package org.tikv.raw; | ||||
| 
 | ||||
| import static org.junit.Assert.*; | ||||
| 
 | ||||
| import com.google.protobuf.ByteString; | ||||
| import java.io.IOException; | ||||
| import java.util.*; | ||||
|  | @ -103,16 +105,16 @@ public class RawKVClientTest { | |||
|     ByteString value2 = ByteString.copyFromUtf8("value2"); | ||||
|     client.delete(key); | ||||
|     ByteString res1 = client.putIfAbsent(key, value, ttl); | ||||
|     assert res1.isEmpty(); | ||||
|     assertTrue(res1.isEmpty()); | ||||
|     ByteString res2 = client.putIfAbsent(key, value2, ttl); | ||||
|     assert res2.equals(value); | ||||
|     assertEquals(value, res2); | ||||
|     try { | ||||
|       Thread.sleep(ttl * 1000); | ||||
|     } catch (InterruptedException e) { | ||||
|       Thread.currentThread().interrupt(); | ||||
|     } | ||||
|     ByteString res3 = client.putIfAbsent(key, value, ttl); | ||||
|     assert res3.isEmpty(); | ||||
|     assertTrue(res3.isEmpty()); | ||||
|   } | ||||
| 
 | ||||
|   // tikv-4.0 doest not support ttl | ||||
|  | @ -258,30 +260,47 @@ public class RawKVClientTest { | |||
|   public void simpleTest() { | ||||
|     if (!initialized) return; | ||||
|     ByteString key = rawKey("key"); | ||||
|     ByteString key0 = rawKey("key0"); | ||||
|     ByteString key1 = rawKey("key1"); | ||||
|     ByteString key2 = rawKey("key2"); | ||||
|     ByteString key3 = rawKey("key3"); | ||||
|     ByteString value = rawValue("value"); | ||||
|     ByteString value1 = rawValue("value1"); | ||||
|     ByteString value2 = rawValue("value2"); | ||||
|     ByteString value3 = rawValue("value3"); | ||||
|     Kvrpcpb.KvPair kv = Kvrpcpb.KvPair.newBuilder().setKey(key).setValue(value).build(); | ||||
|     Kvrpcpb.KvPair kv1 = Kvrpcpb.KvPair.newBuilder().setKey(key1).setValue(value1).build(); | ||||
|     Kvrpcpb.KvPair kv2 = Kvrpcpb.KvPair.newBuilder().setKey(key2).setValue(value2).build(); | ||||
|     Kvrpcpb.KvPair kv3 = Kvrpcpb.KvPair.newBuilder().setKey(key3).setValue(value3).build(); | ||||
| 
 | ||||
|     try { | ||||
|       checkEmpty(key1); | ||||
|       checkEmpty(key2); | ||||
|       checkPut(key1, value1); | ||||
|       checkPut(key2, value2); | ||||
|       List<Kvrpcpb.KvPair> result = new ArrayList<>(); | ||||
|       List<Kvrpcpb.KvPair> result2 = new ArrayList<>(); | ||||
|       result.add(kv1); | ||||
|       result.add(kv2); | ||||
|       checkScan(key, key3, result, limit); | ||||
|       checkScan(key1, key3, result, limit); | ||||
|       checkScan(key, key1, new ArrayList<>(), limit); | ||||
|       result2.add(kv1); | ||||
|       checkScan(key, key2, result2, limit); | ||||
|       checkDeleteRange(ByteString.EMPTY, ByteString.EMPTY); | ||||
|       checkEmpty(kv); | ||||
|       checkEmpty(kv1); | ||||
|       checkEmpty(kv2); | ||||
|       checkEmpty(kv3); | ||||
|       checkPut(kv); | ||||
|       checkPut(kv1); | ||||
|       checkPut(kv2); | ||||
|       checkPut(kv3); | ||||
|       // <key, value>, <key1,value1>, <key2,value2>, <key3,value3> | ||||
|       // (-∞, +∞) | ||||
|       checkScan(ByteString.EMPTY, ByteString.EMPTY, Arrays.asList(kv, kv1, kv2, kv3), limit); | ||||
|       // (-∞, key3) | ||||
|       checkScan(ByteString.EMPTY, key3, Arrays.asList(kv, kv1, kv2), limit); | ||||
|       // [key1, +∞) | ||||
|       checkScan(key1, ByteString.EMPTY, Arrays.asList(kv1, kv2, kv3), limit); | ||||
|       // [key, key3) | ||||
|       checkScan(key, key3, Arrays.asList(kv, kv1, kv2), limit); | ||||
|       // [key1, key3) | ||||
|       checkScan(key1, key3, Arrays.asList(kv1, kv2), limit); | ||||
|       // [key0, key1) | ||||
|       checkScan(key0, key1, new ArrayList<>(), limit); | ||||
|       // [key, key2) | ||||
|       checkScan(key, key2, Arrays.asList(kv, kv1), limit); | ||||
|       checkDelete(key1); | ||||
|       checkDelete(key2); | ||||
|       checkDeleteRange(ByteString.EMPTY, ByteString.EMPTY); | ||||
|     } catch (final TiKVException e) { | ||||
|       logger.warn("Test fails with Exception: " + e); | ||||
|     } | ||||
|  | @ -513,7 +532,7 @@ public class RawKVClientTest { | |||
|     } else { | ||||
|       int i = 0; | ||||
|       for (Map.Entry<ByteString, ByteString> pair : data.entrySet()) { | ||||
|         assert client.get(pair.getKey()).equals(pair.getValue()); | ||||
|         assertEquals(pair.getValue(), client.get(pair.getKey())); | ||||
|         i++; | ||||
|         if (i >= getCases) { | ||||
|           break; | ||||
|  | @ -765,27 +784,31 @@ public class RawKVClientTest { | |||
|   private void checkBatchGet(List<ByteString> keys) { | ||||
|     List<Kvrpcpb.KvPair> result = client.batchGet(keys); | ||||
|     for (Kvrpcpb.KvPair kvPair : result) { | ||||
|       assert data.containsKey(kvPair.getKey()); | ||||
|       assert kvPair.getValue().equals(data.get(kvPair.getKey())); | ||||
|       assertTrue(data.containsKey(kvPair.getKey())); | ||||
|       assertEquals(data.get(kvPair.getKey()), kvPair.getValue()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private void checkPut(Kvrpcpb.KvPair kv) { | ||||
|     checkPut(kv.getKey(), kv.getValue()); | ||||
|   } | ||||
| 
 | ||||
|   private void checkPut(ByteString key, ByteString value) { | ||||
|     client.put(key, value); | ||||
|     assert client.get(key).equals(value); | ||||
|     assertEquals(value, client.get(key)); | ||||
|   } | ||||
| 
 | ||||
|   private void checkBatchPut(Map<ByteString, ByteString> kvPairs) { | ||||
|     client.batchPut(kvPairs); | ||||
|     for (Map.Entry<ByteString, ByteString> kvPair : kvPairs.entrySet()) { | ||||
|       assert client.get(kvPair.getKey()).equals(kvPair.getValue()); | ||||
|       assertEquals(kvPair.getValue(), client.get(kvPair.getKey())); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private void checkScan( | ||||
|       ByteString startKey, ByteString endKey, List<Kvrpcpb.KvPair> ans, int limit) { | ||||
|       ByteString startKey, ByteString endKey, List<Kvrpcpb.KvPair> expected, int limit) { | ||||
|     List<Kvrpcpb.KvPair> result = client.scan(startKey, endKey, limit); | ||||
|     assert result.equals(ans); | ||||
|     assertEquals(expected, result); | ||||
|   } | ||||
| 
 | ||||
|   private void checkScan( | ||||
|  | @ -822,7 +845,7 @@ public class RawKVClientTest { | |||
|                           .setValue(kvPair.getValue()) | ||||
|                           .build()) | ||||
|               .collect(Collectors.toList()); | ||||
|       assert result.get(i).equals(partialResult); | ||||
|       assertEquals(partialResult, result.get(i)); | ||||
|       i++; | ||||
|     } | ||||
|   } | ||||
|  | @ -834,7 +857,7 @@ public class RawKVClientTest { | |||
|       Pair<ByteString, ByteString> range = ranges.get(i); | ||||
|       List<ByteString> partialResult = | ||||
|           new ArrayList<>(data.subMap(range.first, range.second).keySet()); | ||||
|       assert result.get(i).equals(partialResult); | ||||
|       assertEquals(partialResult, result.get(i)); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -848,31 +871,35 @@ public class RawKVClientTest { | |||
|     logger.info("delete range complete"); | ||||
|     List<Kvrpcpb.KvPair> result = client.scan(startKey, endKey); | ||||
|     logger.info("checking scan complete. number of remaining keys in range: " + result.size()); | ||||
|     assert result.isEmpty(); | ||||
|     assertTrue(result.isEmpty()); | ||||
|   } | ||||
| 
 | ||||
|   private void checkPutTTL(ByteString key, ByteString value, long ttl) { | ||||
|     client.put(key, value, ttl); | ||||
|     assert client.get(key).equals(value); | ||||
|     assertEquals(value, client.get(key)); | ||||
|   } | ||||
| 
 | ||||
|   private void checkGetKeyTTL(ByteString key, long ttl) { | ||||
|     Long t = client.getKeyTTL(key); | ||||
|     assert t != null; | ||||
|     assert t <= ttl && t > 0; | ||||
|     assertNotNull(t); | ||||
|     assertTrue(t <= ttl && t > 0); | ||||
|   } | ||||
| 
 | ||||
|   private void checkGetTTLTimeOut(ByteString key) { | ||||
|     assert client.get(key).isEmpty(); | ||||
|     assertTrue(client.get(key).isEmpty()); | ||||
|   } | ||||
| 
 | ||||
|   private void checkGetKeyTTLTimeOut(ByteString key) { | ||||
|     Long t = client.getKeyTTL(key); | ||||
|     assert t == null; | ||||
|     assertNull(t); | ||||
|   } | ||||
| 
 | ||||
|   private void checkEmpty(Kvrpcpb.KvPair kv) { | ||||
|     checkEmpty(kv.getKey()); | ||||
|   } | ||||
| 
 | ||||
|   private void checkEmpty(ByteString key) { | ||||
|     assert client.get(key).isEmpty(); | ||||
|     assertTrue(client.get(key).isEmpty()); | ||||
|   } | ||||
| 
 | ||||
|   private static ByteString rawKey(String key) { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue