[ 
https://issues.apache.org/jira/browse/HBASE-25272?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17230087#comment-17230087
 ] 

Huaxiang Sun edited comment on HBASE-25272 at 11/11/20, 4:45 PM:
-----------------------------------------------------------------

add the diff here as it is hard to keep the right format in github comments.
{code:java}
diff --git 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ScannerCallableWithReplicas.java
 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ScannerCallableWithReplicas.java
index 5fcc440096..6edaa83d11 100644
--- 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ScannerCallableWithReplicas.java
+++ 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ScannerCallableWithReplicas.java
@@ -18,6 +18,8 @@
 
 package org.apache.hadoop.hbase.client;
 
+import static 
org.apache.hadoop.hbase.client.RegionReplicaUtil.DEFAULT_REPLICA_ID;
+import static 
org.apache.hadoop.hbase.client.RegionReplicaUtil.isScanForSpecificReplicaRegion;
 import 
org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
 
 import java.io.IOException;
@@ -45,10 +47,11 @@ import org.apache.hadoop.hbase.util.Pair;
 
 /**
  * This class has the logic for handling scanners for regions with and without 
replicas.
- * 1. A scan is attempted on the default (primary) region
- * 2. The scanner sends all the RPCs to the default region until it is done, 
or, there
- * is a timeout on the default (a timeout of zero is disallowed).
- * 3. If there is a timeout in (2) above, scanner(s) is opened on the 
non-default replica(s)
+ * 1. A scan is attempted on the default (primary) region, or a specific 
region.
+ * 2. The scanner sends all the RPCs to the default/specific region until it 
is done, or, there
+ * is a timeout on the default/specific region (a timeout of zero is 
disallowed).
+ * 3. If there is a timeout in (2) above, scanner(s) is opened on the 
non-default replica(s) only
+ *    for Consistency.TIMELINE without specific replica id specified.
  * 4. The results from the first successful scanner are taken, and it is 
stored which server
  * returned the results.
  * 5. The next RPCs are done on the above stored server until it is done or 
there is a timeout,
@@ -160,7 +163,7 @@ class ScannerCallableWithReplicas implements 
RetryingCallable<Result[]> {
       RegionLocations rl = null;
       try {
         rl = RpcRetryingCallerWithReadReplicas.getRegionLocations(true,
-            RegionReplicaUtil.DEFAULT_REPLICA_ID, cConnection, tableName,
+            DEFAULT_REPLICA_ID, cConnection, tableName,
             currentScannerCallable.getRow());
       } catch (RetriesExhaustedException | DoNotRetryIOException e) {
         // We cannot get the primary replica region location, it is possible 
that the region server
@@ -209,9 +212,10 @@ class ScannerCallableWithReplicas implements 
RetryingCallable<Result[]> {
         LOG.debug("Scan with primary region returns " + e.getCause());
       }
 
-      // If rl's size is 1 or scan's consitency is strong, it needs to throw
-      // out the exception from the primary replica
-      if ((regionReplication == 1) || (scan.getConsistency() == 
Consistency.STRONG)) {
+      // If rl's size is 1 or scan's consitency is strong, or scan is over 
specific replica,
+      // it needs to throw out the exception from the primary replica
+      if ((regionReplication == 1) || (scan.getConsistency() == 
Consistency.STRONG) ||
+        isScanForSpecificReplicaRegion(scan)) {
         // Rethrow the first exception
         RpcRetryingCallerWithReadReplicas.throwEnrichedException(e, retries);
       }
@@ -225,8 +229,9 @@ class ScannerCallableWithReplicas implements 
RetryingCallable<Result[]> {
 
     // submit call for the all of the secondaries at once
     int endIndex = regionReplication;
-    if (scan.getConsistency() == Consistency.STRONG) {
-      // When scan's consistency is strong, do not send to the secondaries
+    if ((scan.getConsistency() == Consistency.STRONG) || 
isScanForSpecificReplicaRegion(scan)){
+      // When scan's consistency is strong or scan is over specific replica 
region,
+      // do not send to other replica regions.
       endIndex = 1;
     } else {
       // TODO: this may be an overkill for large region replication
@@ -376,11 +381,13 @@ class ScannerCallableWithReplicas implements 
RetryingCallable<Result[]> {
       this.callable = callable;
       // For the Consistency.STRONG (default case), we reuse the caller
       // to keep compatibility with what is done in the past
-      // For the Consistency.TIMELINE case, we can't reuse the caller
+      // For the Consistency.TIMELINE case, there are two cases. The first 
case is that
+      // caller targets to a specific replica region, it can reuse the caller.
+      // Otherwise, we can't reuse the caller
       // since we could be making parallel RPCs (caller.callWithRetries is 
synchronized
       // and we can't invoke it multiple times at the same time)
       this.caller = ScannerCallableWithReplicas.this.caller;
-      if (scan.getConsistency() == Consistency.TIMELINE) {
+      if (!isScanForSpecificReplicaRegion(scan)) {
         this.caller = 
RpcRetryingCallerFactory.instantiate(ScannerCallableWithReplicas.this.conf)
             .<Result[]>newCaller();
       }

/**
 * Tell if the input scan targets for a specific replica region in TIMELINE 
mode.
 * @param scan Scan object
 * @return
 */
public static boolean isScanForSpecificReplicaRegion(final Scan scan) {
  return (scan.getConsistency() == Consistency.TIMELINE) && 
(scan.getReplicaId() >= 0);
}

{code}


was (Author: huaxiangsun):
add the diff here as it is hard to keep the right format in github comments.
{code:java}
diff --git 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ScannerCallableWithReplicas.java
 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ScannerCallableWithReplicas.java
index 5fcc440096..6edaa83d11 100644
--- 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ScannerCallableWithReplicas.java
+++ 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ScannerCallableWithReplicas.java
@@ -18,6 +18,8 @@
 
 package org.apache.hadoop.hbase.client;
 
+import static 
org.apache.hadoop.hbase.client.RegionReplicaUtil.DEFAULT_REPLICA_ID;
+import static 
org.apache.hadoop.hbase.client.RegionReplicaUtil.isScanForSpecificReplicaRegion;
 import 
org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
 
 import java.io.IOException;
@@ -45,10 +47,11 @@ import org.apache.hadoop.hbase.util.Pair;
 
 /**
  * This class has the logic for handling scanners for regions with and without 
replicas.
- * 1. A scan is attempted on the default (primary) region
- * 2. The scanner sends all the RPCs to the default region until it is done, 
or, there
- * is a timeout on the default (a timeout of zero is disallowed).
- * 3. If there is a timeout in (2) above, scanner(s) is opened on the 
non-default replica(s)
+ * 1. A scan is attempted on the default (primary) region, or a specific 
region.
+ * 2. The scanner sends all the RPCs to the default/specific region until it 
is done, or, there
+ * is a timeout on the default/specific region (a timeout of zero is 
disallowed).
+ * 3. If there is a timeout in (2) above, scanner(s) is opened on the 
non-default replica(s) only
+ *    for Consistency.TIMELINE without specific replica id specified.
  * 4. The results from the first successful scanner are taken, and it is 
stored which server
  * returned the results.
  * 5. The next RPCs are done on the above stored server until it is done or 
there is a timeout,
@@ -160,7 +163,7 @@ class ScannerCallableWithReplicas implements 
RetryingCallable<Result[]> {
       RegionLocations rl = null;
       try {
         rl = RpcRetryingCallerWithReadReplicas.getRegionLocations(true,
-            RegionReplicaUtil.DEFAULT_REPLICA_ID, cConnection, tableName,
+            DEFAULT_REPLICA_ID, cConnection, tableName,
             currentScannerCallable.getRow());
       } catch (RetriesExhaustedException | DoNotRetryIOException e) {
         // We cannot get the primary replica region location, it is possible 
that the region server
@@ -209,9 +212,10 @@ class ScannerCallableWithReplicas implements 
RetryingCallable<Result[]> {
         LOG.debug("Scan with primary region returns " + e.getCause());
       }
 
-      // If rl's size is 1 or scan's consitency is strong, it needs to throw
-      // out the exception from the primary replica
-      if ((regionReplication == 1) || (scan.getConsistency() == 
Consistency.STRONG)) {
+      // If rl's size is 1 or scan's consitency is strong, or scan is over 
specific replica,
+      // it needs to throw out the exception from the primary replica
+      if ((regionReplication == 1) || (scan.getConsistency() == 
Consistency.STRONG) ||
+        isScanForSpecificReplicaRegion(scan)) {
         // Rethrow the first exception
         RpcRetryingCallerWithReadReplicas.throwEnrichedException(e, retries);
       }
@@ -225,8 +229,9 @@ class ScannerCallableWithReplicas implements 
RetryingCallable<Result[]> {
 
     // submit call for the all of the secondaries at once
     int endIndex = regionReplication;
-    if (scan.getConsistency() == Consistency.STRONG) {
-      // When scan's consistency is strong, do not send to the secondaries
+    if ((scan.getConsistency() == Consistency.STRONG) || 
isScanForSpecificReplicaRegion(scan)){
+      // When scan's consistency is strong or scan is over specific replica 
region,
+      // do not send to other replica regions.
       endIndex = 1;
     } else {
       // TODO: this may be an overkill for large region replication
@@ -376,11 +381,13 @@ class ScannerCallableWithReplicas implements 
RetryingCallable<Result[]> {
       this.callable = callable;
       // For the Consistency.STRONG (default case), we reuse the caller
       // to keep compatibility with what is done in the past
-      // For the Consistency.TIMELINE case, we can't reuse the caller
+      // For the Consistency.TIMELINE case, there are two cases. The first 
case is that
+      // caller targets to a specific replica region, it can reuse the caller.
+      // Otherwise, we can't reuse the caller
       // since we could be making parallel RPCs (caller.callWithRetries is 
synchronized
       // and we can't invoke it multiple times at the same time)
       this.caller = ScannerCallableWithReplicas.this.caller;
-      if (scan.getConsistency() == Consistency.TIMELINE) {
+      if (!isScanForSpecificReplicaRegion(scan)) {
         this.caller = 
RpcRetryingCallerFactory.instantiate(ScannerCallableWithReplicas.this.conf)
             .<Result[]>newCaller();
       }
{code}

> Support scan on a specific replica
> ----------------------------------
>
>                 Key: HBASE-25272
>                 URL: https://issues.apache.org/jira/browse/HBASE-25272
>             Project: HBase
>          Issue Type: Improvement
>          Components: Client, scan
>            Reporter: Duo Zhang
>            Assignee: Duo Zhang
>            Priority: Critical
>             Fix For: 2.4.0
>
>
> This is a missing part of the client library for sync client on branch-2, and 
> it is necessary when implementing meta replicas read.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to