View Javadoc

1   /**
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.client;
22  
23  import java.io.IOException;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.hadoop.hbase.DoNotRetryIOException;
28  import org.apache.hadoop.hbase.HRegionInfo;
29  import org.apache.hadoop.hbase.NotServingRegionException;
30  import org.apache.hadoop.hbase.RemoteExceptionHandler;
31  import org.apache.hadoop.hbase.regionserver.RegionServerStoppedException;
32  import org.apache.hadoop.ipc.RemoteException;
33  
34  
35  /**
36   * Retries scanner operations such as create, next, etc.
37   * Used by {@link ResultScanner}s made by {@link HTable}.
38   */
39  public class ScannerCallable extends ServerCallable<Result[]> {
40    private static final Log LOG = LogFactory.getLog(ScannerCallable.class);
41    private long scannerId = -1L;
42    private boolean instantiated = false;
43    private boolean closed = false;
44    private Scan scan;
45    private int caching = 1;
46  
47    /**
48     * @param connection which connection
49     * @param tableName table callable is on
50     * @param scan the scan to execute
51     */
52    public ScannerCallable (HConnection connection, byte [] tableName, Scan scan) {
53      super(connection, tableName, scan.getStartRow());
54      this.scan = scan;
55    }
56  
57    /**
58     * @param reload force reload of server location
59     * @throws IOException
60     */
61    @Override
62    public void connect(boolean reload) throws IOException {
63      if (!instantiated || reload) {
64        super.connect(reload);
65        instantiated = true;
66      }
67    }
68  
69    /**
70     * @see java.util.concurrent.Callable#call()
71     */
72    public Result [] call() throws IOException {
73      if (scannerId != -1L && closed) {
74        close();
75      } else if (scannerId == -1L && !closed) {
76        this.scannerId = openScanner();
77      } else {
78        Result [] rrs = null;
79        try {
80          rrs = server.next(scannerId, caching);
81        } catch (IOException e) {
82          IOException ioe = null;
83          if (e instanceof RemoteException) {
84            ioe = RemoteExceptionHandler.decodeRemoteException((RemoteException)e);
85          }
86          if (ioe == null) throw new IOException(e);
87          if (ioe instanceof NotServingRegionException) {
88            // Throw a DNRE so that we break out of cycle of calling NSRE
89            // when what we need is to open scanner against new location.
90            // Attach NSRE to signal client that it needs to resetup scanner.
91            throw new DoNotRetryIOException("Reset scanner", ioe);
92          } else if (ioe instanceof RegionServerStoppedException) {
93            // Throw a DNRE so that we break out of cycle of calling RSSE
94            // when what we need is to open scanner against new location.
95            // Attach RSSE to signal client that it needs to resetup scanner.
96            throw new DoNotRetryIOException("Reset scanner", ioe);
97          } else {
98            // The outer layers will retry
99            throw ioe;
100         }
101       }
102       return rrs;
103     }
104     return null;
105   }
106 
107   private void close() {
108     if (this.scannerId == -1L) {
109       return;
110     }
111     try {
112       this.server.close(this.scannerId);
113     } catch (IOException e) {
114       LOG.warn("Ignore, probably already closed", e);
115     }
116     this.scannerId = -1L;
117   }
118 
119   protected long openScanner() throws IOException {
120     return this.server.openScanner(this.location.getRegionInfo().getRegionName(),
121       this.scan);
122   }
123 
124   protected Scan getScan() {
125     return scan;
126   }
127 
128   /**
129    * Call this when the next invocation of call should close the scanner
130    */
131   public void setClose() {
132     this.closed = true;
133   }
134 
135   /**
136    * @return the HRegionInfo for the current region
137    */
138   public HRegionInfo getHRegionInfo() {
139     if (!instantiated) {
140       return null;
141     }
142     return location.getRegionInfo();
143   }
144 
145   /**
146    * Get the number of rows that will be fetched on next
147    * @return the number of rows for caching
148    */
149   public int getCaching() {
150     return caching;
151   }
152 
153   /**
154    * Set the number of rows that will be fetched on next
155    * @param caching the number of rows for caching
156    */
157   public void setCaching(int caching) {
158     this.caching = caching;
159   }
160 }