This is an automated email from the ASF dual-hosted git repository.

alexey pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git


The following commit(s) were added to refs/heads/master by this push:
     new dec3026  KUDU-3273: check result of TableLocationsCache.get() for null
dec3026 is described below

commit dec30269cac84e0cbc589145a7685f24e0976592
Author: Li Zhiming <[email protected]>
AuthorDate: Thu Apr 8 16:36:29 2021 +0800

    KUDU-3273: check result of TableLocationsCache.get() for null
    
    For TableLocationsCache, if get(key) is called immediately after
    cacheTabletLocations(key), it should not return null.
    But if partitions change and a call to cacheTabletLocations(otherKey)
    occurs between calls to cacheTableLocations(key) and get(key), the
    latter might return null.
    
    Change-Id: I13475701804ea4ae2bf8089a1e2b9143a12d2ab9
    Reviewed-on: http://gerrit.cloudera.org:8080/17288
    Tested-by: Alexey Serbin <[email protected]>
    Reviewed-by: Alexey Serbin <[email protected]>
---
 .../org/apache/kudu/client/AsyncKuduClient.java    |  5 ++--
 .../org/apache/kudu/client/TestRemoteTablet.java   | 13 ++++++++-
 .../kudu/client/TestTableLocationsCache.java       | 31 ++++++++++++++++++++++
 .../java/org/apache/kudu/test/ProtobufUtils.java   | 14 ++++++++++
 4 files changed, 60 insertions(+), 3 deletions(-)

diff --git 
a/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java 
b/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java
index 34996a5..90edce4 100644
--- a/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java
+++ b/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java
@@ -2427,9 +2427,10 @@ public class AsyncKuduClient implements AutoCloseable {
     // right away. If not, we throw an exception that RetryRpcErrback will 
understand as needing to
     // sleep before retrying.
     TableLocationsCache.Entry entry = locationsCache.get(requestPartitionKey);
-    if (!entry.isNonCoveredRange() && entry.getTablet().getLeaderServerInfo() 
== null) {
+    if (entry != null && !entry.isNonCoveredRange() &&
+        entry.getTablet().getLeaderServerInfo() == null) {
       throw new NoLeaderFoundException(
-          Status.NotFound("Tablet " + entry.toString() + " doesn't have a 
leader"));
+          Status.NotFound("Tablet " + entry + " doesn't have a leader"));
     }
   }
 
diff --git 
a/java/kudu-client/src/test/java/org/apache/kudu/client/TestRemoteTablet.java 
b/java/kudu-client/src/test/java/org/apache/kudu/client/TestRemoteTablet.java
index 94aa31b..c3e063a 100644
--- 
a/java/kudu-client/src/test/java/org/apache/kudu/client/TestRemoteTablet.java
+++ 
b/java/kudu-client/src/test/java/org/apache/kudu/client/TestRemoteTablet.java
@@ -257,7 +257,18 @@ public class TestRemoteTablet {
   static RemoteTablet getTablet(int leaderIndex,
                                 int localReplicaIndex,
                                 int sameLocationReplicaIndex) {
-    Partition partition = 
ProtobufHelper.pbToPartition(ProtobufUtils.getFakePartitionPB().build());
+    return getTablet(
+            leaderIndex, localReplicaIndex, sameLocationReplicaIndex,
+            AsyncKuduClient.EMPTY_ARRAY, AsyncKuduClient.EMPTY_ARRAY);
+  }
+
+  static RemoteTablet getTablet(int leaderIndex,
+                                int localReplicaIndex,
+                                int sameLocationReplicaIndex,
+                                byte[] partitionKeyStart,
+                                byte[] partitionKeyEnd) {
+    Partition partition = ProtobufHelper.pbToPartition(
+            ProtobufUtils.getFakePartitionPB(partitionKeyStart, 
partitionKeyEnd).build());
     List<LocatedTablet.Replica> replicas = new ArrayList<>();
     List<ServerInfo> servers = new ArrayList<>();
     for (int i = 0; i < 3; i++) {
diff --git 
a/java/kudu-client/src/test/java/org/apache/kudu/client/TestTableLocationsCache.java
 
b/java/kudu-client/src/test/java/org/apache/kudu/client/TestTableLocationsCache.java
index b232bd4..0f0ce1a 100644
--- 
a/java/kudu-client/src/test/java/org/apache/kudu/client/TestTableLocationsCache.java
+++ 
b/java/kudu-client/src/test/java/org/apache/kudu/client/TestTableLocationsCache.java
@@ -18,7 +18,10 @@
 package org.apache.kudu.client;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 
+import java.nio.charset.StandardCharsets;
 import java.util.List;
 
 import com.google.common.base.Ticker;
@@ -67,4 +70,32 @@ public class TestTableLocationsCache {
                  "ttl=90, tablet=" + tablet.toString() + "}]",
                  cache.toString());
   }
+
+  /**
+   * Test to reproduce the issue in KUDU-3273.
+   *
+   * For TableLocationsCache, if get(key) is called immediately after
+   * cacheTabletLocations(key), it should not return null.
+   * But if partitions change and a call to cacheTabletLocations(otherKey)
+   * occurs between calls to cacheTableLocations(key) and get(key),
+   * the latter might return null.
+   */
+  @Test
+  public void testGet() {
+    byte[] keyB = "b".getBytes(StandardCharsets.UTF_8);
+    List<RemoteTablet> tablets = ImmutableList.of(
+            TestRemoteTablet.getTablet(0, 1, -1, keyB, 
AsyncKuduClient.EMPTY_ARRAY));
+    cache.cacheTabletLocations(tablets, AsyncKuduClient.EMPTY_ARRAY, 1, 100);
+    assertNotNull(cache.get(AsyncKuduClient.EMPTY_ARRAY));
+
+    byte[] keyA = "a".getBytes(StandardCharsets.UTF_8);
+    tablets = ImmutableList.of(
+            TestRemoteTablet.getTablet(0, 1, -1, keyA, 
AsyncKuduClient.EMPTY_ARRAY));
+    cache.cacheTabletLocations(tablets, keyA, 1, 100);
+
+    assertNull(cache.get(AsyncKuduClient.EMPTY_ARRAY));
+
+    cache.cacheTabletLocations(tablets, AsyncKuduClient.EMPTY_ARRAY, 1, 100);
+    assertNotNull(cache.get(AsyncKuduClient.EMPTY_ARRAY));
+  }
 }
diff --git 
a/java/kudu-test-utils/src/main/java/org/apache/kudu/test/ProtobufUtils.java 
b/java/kudu-test-utils/src/main/java/org/apache/kudu/test/ProtobufUtils.java
index 862439a..93a79a7 100644
--- a/java/kudu-test-utils/src/main/java/org/apache/kudu/test/ProtobufUtils.java
+++ b/java/kudu-test-utils/src/main/java/org/apache/kudu/test/ProtobufUtils.java
@@ -41,6 +41,20 @@ public class ProtobufUtils {
   }
 
   /**
+   * Get a PartitionPB with specified start and end keys.
+   * @param partitionKeyStart start key
+   * @param partitionKeyEnd end key
+   * @return a fake partition
+   */
+  public static Common.PartitionPB.Builder getFakePartitionPB(
+          byte[] partitionKeyStart, byte[] partitionKeyEnd) {
+    Common.PartitionPB.Builder partition = Common.PartitionPB.newBuilder();
+    partition.setPartitionKeyStart(ByteString.copyFrom(partitionKeyStart));
+    partition.setPartitionKeyEnd(ByteString.copyFrom(partitionKeyEnd));
+    return partition;
+  }
+
+  /**
    * Create a InternedReplicaPB based on the passed information.
    * @param tsInfoIndex server's index in the TSInfoPB list
    * @param role server's role in the configuration

Reply via email to