[ 
https://issues.apache.org/jira/browse/HADOOP-2555?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12558191#action_12558191
 ] 

Bryan Duxbury commented on HADOOP-2555:
---------------------------------------

Generally, I love this patch. It'll nicely reduce the amount of copy-paste we 
have.

I'd like to maybe take it one step further, though. Instead of the existing 
callServerWithRetries, how about something like:

{code}

  protected abstract class ServerCallable<T> implements Callable<T> {
    HRegionLocation location;
    HRegionInterface server;
    Text row;
    
    protected ServerCallable(Text row){
      this.row = row;
    }
    
    void instantiateServer(boolean reload) throws IOException {
      if (reload) {
        tableServers = connection.reloadTableServers(tableName);
      }
      location = getRegionLocation(row);
      server = connection.getHRegionConnection(location.getServerAddress());
    }
  }
  
  protected <T> T getRegionServerWithRetries(ServerCallable<T> callable) 
  throws IOException, UnexpectedCallableException {
    for(int tries = 0; tries < numRetries; tries++) {
      try {
        callable.instantiateServer(tries == 0);
        return callable.call();
      } catch (IOException e) {
        if (e instanceof RemoteException) {
          e = RemoteExceptionHandler.decodeRemoteException((RemoteException) e);
        }
        if (tries == numRetries - 1) {
          throw e;
        }
        if (LOG.isDebugEnabled()) {
          LOG.debug("reloading table servers because: " + e.getMessage());
        }
      } catch (Exception e) {
        throw new UnexpectedCallableException(e);
      }
      try {
        Thread.sleep(pause);
      } catch (InterruptedException e) {
        // continue
      }
    }
    return null;    
  }
{code}

which takes us from 

{code}
value = this.callServerWithRetries(new Callable<MapWritable>() {
  public MapWritable call() throws IOException {
    HRegionLocation r = getRegionLocation(row);
    HRegionInterface server =
      connection.getHRegionConnection(r.getServerAddress());
    return server.getRow(r.getRegionInfo().getRegionName(), row, ts);
  }
});
{code}

to 

{code}
value = this.callServerWithRetries(new ServerCallable<MapWritable>(row) {
  public MapWritable call() throws IOException {
  return server.getRow(location.getRegionInfo().getRegionName(), row, ts);
  }
});
{code}

This would save a few lines of code inside each internal block, move a little 
more logic into the helper method, and generally jive better with the way my 
HADOOP-2443 patch is going to need to work in the near future. 

Comments?

> Refactor the HTable#get and HTable#getRow methods to avoid repetition of 
> retry-on-failure logic
> -----------------------------------------------------------------------------------------------
>
>                 Key: HADOOP-2555
>                 URL: https://issues.apache.org/jira/browse/HADOOP-2555
>             Project: Hadoop
>          Issue Type: Improvement
>          Components: contrib/hbase
>            Reporter: Peter Dolan
>            Priority: Minor
>         Attachments: hadoop-2555.patch
>
>
> The following code is repeated in every one of HTable#get and HTable#getRow 
> methods:
> {code:title=HTable.java|borderStyle=solid}
>     MapWritable value = null;
>     for (int tries = 0; tries < numRetries; tries++) {
>       HRegionLocation r = getRegionLocation(row);
>       HRegionInterface server =
>         connection.getHRegionConnection(r.getServerAddress());
>       
>       try {
>         value = server.getRow(r.getRegionInfo().getRegionName(), row, ts);  
> // This is the only line of code that changes significantly between methods
>         break;
>         
>       } catch (IOException e) {
>         if (e instanceof RemoteException) {
>           e = RemoteExceptionHandler.decodeRemoteException((RemoteException) 
> e);
>         }
>         if (tries == numRetries - 1) {
>           // No more tries
>           throw e;
>         }
>         if (LOG.isDebugEnabled()) {
>           LOG.debug("reloading table servers because: " + e.getMessage());
>         }
>         tableServers = connection.reloadTableServers(tableName);
>       }
>       try {
>         Thread.sleep(this.pause);
>         
>       } catch (InterruptedException x) {
>         // continue
>       }
>     }
> {code}
> This should be factored out into a protected method that handles 
> retry-on-failure logic to facilitate more robust testing and the development 
> of new API methods.
> Proposed modification:
> // Execute the provided Callable against the server
> protected <T> callServerWithRetries(Callable<T> callable) throws 
> RemoteException;
> The above code could then be reduced to:
> {code:title=HTable.java|borderStyle=solid}
>     MapWritable value = null;
>     final connection;
>     try {
>       value = callServerWithRetries(new Callable<MapWritable>() {
>             HRegionLocation r = getRegionLocation(row);
>             HRegionInterface server =
>                 connection.getHRegionConnection(r.getServerAddress());
>             server.getRow(r.getRegionInfo().getRegionName(), row, ts);
>           });
>     } catch (RemoteException e) {
>       // handle unrecoverable remote exceptions
>     }
> {code}
> This would greatly ease the development of new API methods by reducing the 
> amount of code needed to implement a new method and reducing the amount of 
> logic that needs to be tested per method.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to