Will Berkeley created KUDU-2710:
-----------------------------------

             Summary: Retries of scanner keep alive requests are broken in the 
Java client
                 Key: KUDU-2710
                 URL: https://issues.apache.org/jira/browse/KUDU-2710
             Project: Kudu
          Issue Type: Bug
    Affects Versions: 1.9.0
            Reporter: Will Berkeley
            Assignee: Will Berkeley


KuduRpc implements a default `partitionKey` method:

{noformat}
/**
   * Returns the partition key this RPC is for, or {@code null} if the RPC is
   * not tablet specific.
   * <p>
   * <strong>DO NOT MODIFY THE CONTENTS OF THE RETURNED ARRAY.</strong>
   */
  byte[] partitionKey() {
    return null;
  }
{noformat}

Subclasses override this method to indicate the start key of the tablet they 
should be sent to, and the Java client uses this, in part, to select which 
tserver to send retries to. The default implementation returns {{null}}, which 
is a special value that is only valid as a partition key for the master table. 
The keep alive RPC does not override this method, so it uses the default 
implementation.

When {{KuduScanner#keepAlive}} is called, the initial keep alive RPC does not 
use {{partitionKey}}, so it works OK. However, retries go through standard 
retry logic, which calls {{delayedSendRpcToTablet}}, which calls 
{{sendRpcToTablet}} after a delay and on a timer thread. In {{sendRpcToTablet}} 
we call {{getTableLocationEntry}} with a null {{partitionkey}}, because the RPC 
never set one. That results in {{cache.get(partitionKey)}} throwing an 
exception (usually) because there are multiple entries in the cache for the 
table, but the {{null}} partition key makes the lookup act like it is looking 
up the master table, so the invariant check for the master table 
{{Preconditions.checkState(entries.size() <= 1)}} fails.

As a workaround, users can set {{keepAlivePeriodMs}} on {{KuduReadOptions}} to 
something very large like {{Long.MAX_VALUE}}; or, if using the default source, 
pass the {{kudu.keepAlivePeriodMs}} spark config with a very large value. Note 
that there also has to be something causing keep alive requests to fail and 
retry, and this is relatively rare (in my experience).

To fix, we'll need to make sure that keep alive RPCs act like scan RPCs, and 
are always retried on the same server as the one currently open for scanning 
(or no op if there is no such server).

Also, it's not wise to keep the default implementation in KuduRpc-- subclasses 
ought to have to make an explicit choice about the default partition key, which 
is a proxy for which tablet they will go to.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to