Search in sources :

Example 1 with ScannerResetException

use of org.apache.hadoop.hbase.exceptions.ScannerResetException in project hbase by apache.

the class TestFromClientSide method testScannerFailsAfterRetriesWhenCoprocessorThrowsIOE.

/**
   * Tests the case where a coprocessor throws a regular IOException in the scan. The expectation
   * is that the we will keep on retrying, but fail after the retries are exhausted instead of
   * retrying indefinitely.
   */
@Test(timeout = 180000)
public void testScannerFailsAfterRetriesWhenCoprocessorThrowsIOE() throws IOException, InterruptedException {
    TEST_UTIL.getConfiguration().setBoolean("hbase.client.log.scanner.activity", true);
    final TableName tableName = TableName.valueOf(name.getMethodName());
    TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 3);
    HTableDescriptor htd = TEST_UTIL.createTableDescriptor(tableName, FAMILY);
    htd.addCoprocessor(ExceptionInReseekRegionObserver.class.getName());
    TEST_UTIL.getAdmin().createTable(htd);
    ExceptionInReseekRegionObserver.reset();
    // throw exceptions in every retry
    ExceptionInReseekRegionObserver.throwOnce.set(false);
    try (Table t = TEST_UTIL.getConnection().getTable(tableName)) {
        TEST_UTIL.loadTable(t, FAMILY, false);
        TEST_UTIL.getAdmin().flush(tableName);
        TEST_UTIL.countRows(t, new Scan().addColumn(FAMILY, FAMILY));
        fail("Should have thrown an exception");
    } catch (DoNotRetryIOException expected) {
        assertTrue(expected instanceof ScannerResetException);
    // expected
    }
    assertTrue(ExceptionInReseekRegionObserver.reqCount.get() >= 3);
}
Also used : TableName(org.apache.hadoop.hbase.TableName) DoNotRetryIOException(org.apache.hadoop.hbase.DoNotRetryIOException) ScannerResetException(org.apache.hadoop.hbase.exceptions.ScannerResetException) HTableDescriptor(org.apache.hadoop.hbase.HTableDescriptor) Test(org.junit.Test)

Example 2 with ScannerResetException

use of org.apache.hadoop.hbase.exceptions.ScannerResetException in project hbase by apache.

the class RSRpcServices method scan.

/**
 * Scan data in a table.
 *
 * @param controller the RPC controller
 * @param request the scan request
 * @throws ServiceException
 */
@Override
public ScanResponse scan(final RpcController controller, final ScanRequest request) throws ServiceException {
    if (controller != null && !(controller instanceof HBaseRpcController)) {
        throw new UnsupportedOperationException("We only do " + "HBaseRpcControllers! FIX IF A PROBLEM: " + controller);
    }
    if (!request.hasScannerId() && !request.hasScan()) {
        throw new ServiceException(new DoNotRetryIOException("Missing required input: scannerId or scan"));
    }
    try {
        checkOpen();
    } catch (IOException e) {
        if (request.hasScannerId()) {
            String scannerName = toScannerName(request.getScannerId());
            if (LOG.isDebugEnabled()) {
                LOG.debug("Server shutting down and client tried to access missing scanner " + scannerName);
            }
            final LeaseManager leaseManager = server.getLeaseManager();
            if (leaseManager != null) {
                try {
                    leaseManager.cancelLease(scannerName);
                } catch (LeaseException le) {
                    // No problem, ignore
                    if (LOG.isTraceEnabled()) {
                        LOG.trace("Un-able to cancel lease of scanner. It could already be closed.");
                    }
                }
            }
        }
        throw new ServiceException(e);
    }
    requestCount.increment();
    rpcScanRequestCount.increment();
    RegionScannerHolder rsh;
    ScanResponse.Builder builder = ScanResponse.newBuilder();
    String scannerName;
    try {
        if (request.hasScannerId()) {
            // The downstream projects such as AsyncHBase in OpenTSDB need this value. See HBASE-18000
            // for more details.
            long scannerId = request.getScannerId();
            builder.setScannerId(scannerId);
            scannerName = toScannerName(scannerId);
            rsh = getRegionScanner(request);
        } else {
            Pair<String, RegionScannerHolder> scannerNameAndRSH = newRegionScanner(request, builder);
            scannerName = scannerNameAndRSH.getFirst();
            rsh = scannerNameAndRSH.getSecond();
        }
    } catch (IOException e) {
        if (e == SCANNER_ALREADY_CLOSED) {
            // the old client will still send a close request to us. Just ignore it and return.
            return builder.build();
        }
        throw new ServiceException(e);
    }
    if (rsh.fullRegionScan) {
        rpcFullScanRequestCount.increment();
    }
    HRegion region = rsh.r;
    LeaseManager.Lease lease;
    try {
        // Remove lease while its being processed in server; protects against case
        // where processing of request takes > lease expiration time. or null if none found.
        lease = server.getLeaseManager().removeLease(scannerName);
    } catch (LeaseException e) {
        throw new ServiceException(e);
    }
    if (request.hasRenew() && request.getRenew()) {
        // add back and return
        addScannerLeaseBack(lease);
        try {
            checkScanNextCallSeq(request, rsh);
        } catch (OutOfOrderScannerNextException e) {
            throw new ServiceException(e);
        }
        return builder.build();
    }
    OperationQuota quota;
    try {
        quota = getRpcQuotaManager().checkQuota(region, OperationQuota.OperationType.SCAN);
    } catch (IOException e) {
        addScannerLeaseBack(lease);
        throw new ServiceException(e);
    }
    try {
        checkScanNextCallSeq(request, rsh);
    } catch (OutOfOrderScannerNextException e) {
        addScannerLeaseBack(lease);
        throw new ServiceException(e);
    }
    // Now we have increased the next call sequence. If we give client an error, the retry will
    // never success. So we'd better close the scanner and return a DoNotRetryIOException to client
    // and then client will try to open a new scanner.
    boolean closeScanner = request.hasCloseScanner() ? request.getCloseScanner() : false;
    // this is scan.getCaching
    int rows;
    if (request.hasNumberOfRows()) {
        rows = request.getNumberOfRows();
    } else {
        rows = closeScanner ? 0 : 1;
    }
    RpcCallContext context = RpcServer.getCurrentCall().orElse(null);
    // now let's do the real scan.
    long maxQuotaResultSize = Math.min(maxScannerResultSize, quota.getReadAvailable());
    RegionScanner scanner = rsh.s;
    // this is the limit of rows for this scan, if we the number of rows reach this value, we will
    // close the scanner.
    int limitOfRows;
    if (request.hasLimitOfRows()) {
        limitOfRows = request.getLimitOfRows();
    } else {
        limitOfRows = -1;
    }
    MutableObject<Object> lastBlock = new MutableObject<>();
    boolean scannerClosed = false;
    try {
        List<Result> results = new ArrayList<>(Math.min(rows, 512));
        if (rows > 0) {
            boolean done = false;
            // Call coprocessor. Get region info from scanner.
            if (region.getCoprocessorHost() != null) {
                Boolean bypass = region.getCoprocessorHost().preScannerNext(scanner, results, rows);
                if (!results.isEmpty()) {
                    for (Result r : results) {
                        lastBlock.setValue(addSize(context, r, lastBlock.getValue()));
                    }
                }
                if (bypass != null && bypass.booleanValue()) {
                    done = true;
                }
            }
            if (!done) {
                scan((HBaseRpcController) controller, request, rsh, maxQuotaResultSize, rows, limitOfRows, results, builder, lastBlock, context);
            } else {
                builder.setMoreResultsInRegion(!results.isEmpty());
            }
        } else {
            // This is a open scanner call with numberOfRow = 0, so set more results in region to true.
            builder.setMoreResultsInRegion(true);
        }
        quota.addScanResult(results);
        addResults(builder, results, (HBaseRpcController) controller, RegionReplicaUtil.isDefaultReplica(region.getRegionInfo()), isClientCellBlockSupport(context));
        if (scanner.isFilterDone() && results.isEmpty()) {
            // If the scanner's filter - if any - is done with the scan
            // only set moreResults to false if the results is empty. This is used to keep compatible
            // with the old scan implementation where we just ignore the returned results if moreResults
            // is false. Can remove the isEmpty check after we get rid of the old implementation.
            builder.setMoreResults(false);
        }
        // have already set this flag.
        assert builder.hasMoreResultsInRegion();
        // yet.
        if (!builder.hasMoreResults()) {
            builder.setMoreResults(true);
        }
        if (builder.getMoreResults() && builder.getMoreResultsInRegion() && !results.isEmpty()) {
            // Record the last cell of the last result if it is a partial result
            // We need this to calculate the complete rows we have returned to client as the
            // mayHaveMoreCellsInRow is true does not mean that there will be extra cells for the
            // current row. We may filter out all the remaining cells for the current row and just
            // return the cells of the nextRow when calling RegionScanner.nextRaw. So here we need to
            // check for row change.
            Result lastResult = results.get(results.size() - 1);
            if (lastResult.mayHaveMoreCellsInRow()) {
                rsh.rowOfLastPartialResult = lastResult.getRow();
            } else {
                rsh.rowOfLastPartialResult = null;
            }
        }
        if (!builder.getMoreResults() || !builder.getMoreResultsInRegion() || closeScanner) {
            scannerClosed = true;
            closeScanner(region, scanner, scannerName, context);
        }
        return builder.build();
    } catch (IOException e) {
        try {
            // scanner is closed here
            scannerClosed = true;
            // The scanner state might be left in a dirty state, so we will tell the Client to
            // fail this RPC and close the scanner while opening up another one from the start of
            // row that the client has last seen.
            closeScanner(region, scanner, scannerName, context);
            // the client. See ClientScanner code to see how it deals with these special exceptions.
            if (e instanceof DoNotRetryIOException) {
                throw e;
            }
            // DoNotRetryIOException. This can avoid the retry in ClientScanner.
            if (e instanceof FileNotFoundException) {
                throw new DoNotRetryIOException(e);
            }
            // a special exception to save an RPC.
            if (VersionInfoUtil.hasMinimumVersion(context.getClientVersionInfo(), 1, 4)) {
                // 1.4.0+ clients know how to handle
                throw new ScannerResetException("Scanner is closed on the server-side", e);
            } else {
                // older clients do not know about SRE. Just throw USE, which they will handle
                throw new UnknownScannerException("Throwing UnknownScannerException to reset the client" + " scanner state for clients older than 1.3.", e);
            }
        } catch (IOException ioe) {
            throw new ServiceException(ioe);
        }
    } finally {
        if (!scannerClosed) {
            // the closeCallBack will be set in closeScanner so here we only care about shippedCallback
            if (context != null) {
                context.setCallBack(rsh.shippedCallback);
            } else {
                // When context != null, adding back the lease will be done in callback set above.
                addScannerLeaseBack(lease);
            }
        }
        quota.close();
    }
}
Also used : DoNotRetryIOException(org.apache.hadoop.hbase.DoNotRetryIOException) ScannerResetException(org.apache.hadoop.hbase.exceptions.ScannerResetException) ArrayList(java.util.ArrayList) FileNotFoundException(java.io.FileNotFoundException) ByteString(org.apache.hbase.thirdparty.com.google.protobuf.ByteString) RegionActionResult(org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.RegionActionResult) Result(org.apache.hadoop.hbase.client.Result) CheckAndMutateResult(org.apache.hadoop.hbase.client.CheckAndMutateResult) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) OutOfOrderScannerNextException(org.apache.hadoop.hbase.exceptions.OutOfOrderScannerNextException) MutableObject(org.apache.commons.lang3.mutable.MutableObject) RpcCallContext(org.apache.hadoop.hbase.ipc.RpcCallContext) Lease(org.apache.hadoop.hbase.regionserver.LeaseManager.Lease) ScanResponse(org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ScanResponse) OperationQuota(org.apache.hadoop.hbase.quotas.OperationQuota) IOException(java.io.IOException) DoNotRetryIOException(org.apache.hadoop.hbase.DoNotRetryIOException) HBaseIOException(org.apache.hadoop.hbase.HBaseIOException) UncheckedIOException(java.io.UncheckedIOException) UnknownScannerException(org.apache.hadoop.hbase.UnknownScannerException) HBaseRpcController(org.apache.hadoop.hbase.ipc.HBaseRpcController) ServiceException(org.apache.hbase.thirdparty.com.google.protobuf.ServiceException) MutableObject(org.apache.commons.lang3.mutable.MutableObject)

Example 3 with ScannerResetException

use of org.apache.hadoop.hbase.exceptions.ScannerResetException in project hbase by apache.

the class AsyncRpcRetryingCaller method onError.

protected final void onError(Throwable t, Supplier<String> errMsg, Consumer<Throwable> updateCachedLocation) {
    if (future.isDone()) {
        // Give up if the future is already done, this is possible if user has already canceled the
        // future. And for timeline consistent read, we will also cancel some requests if we have
        // already get one of the responses.
        LOG.debug("The future is already done, canceled={}, give up retrying", future.isCancelled());
        return;
    }
    Throwable error = preProcessError(translateException(t));
    // exactly trying to open a new scanner, so we should retry on ScannerResetException.
    if (error instanceof DoNotRetryIOException && !(error instanceof ScannerResetException)) {
        future.completeExceptionally(error);
        return;
    }
    if (tries > startLogErrorsCnt) {
        LOG.warn(errMsg.get() + ", tries = " + tries + ", maxAttempts = " + maxAttempts + ", timeout = " + TimeUnit.NANOSECONDS.toMillis(operationTimeoutNs) + " ms, time elapsed = " + elapsedMs() + " ms", error);
    }
    updateCachedLocation.accept(error);
    RetriesExhaustedException.ThrowableWithExtraContext qt = new RetriesExhaustedException.ThrowableWithExtraContext(error, EnvironmentEdgeManager.currentTime(), "");
    exceptions.add(qt);
    if (tries >= maxAttempts) {
        completeExceptionally();
        return;
    }
    // meta, so here we only check for disabled for some specific exception types.
    if (error instanceof NotServingRegionException || error instanceof RegionOfflineException) {
        Optional<TableName> tableName = getTableName();
        if (tableName.isPresent()) {
            FutureUtils.addListener(conn.getAdmin().isTableDisabled(tableName.get()), (disabled, e) -> {
                if (e != null) {
                    if (e instanceof TableNotFoundException) {
                        future.completeExceptionally(e);
                    } else {
                        // failed to test whether the table is disabled, not a big deal, continue retrying
                        tryScheduleRetry(error);
                    }
                    return;
                }
                if (disabled) {
                    future.completeExceptionally(new TableNotEnabledException(tableName.get()));
                } else {
                    tryScheduleRetry(error);
                }
            });
        } else {
            tryScheduleRetry(error);
        }
    } else {
        tryScheduleRetry(error);
    }
}
Also used : TableName(org.apache.hadoop.hbase.TableName) TableNotFoundException(org.apache.hadoop.hbase.TableNotFoundException) DoNotRetryIOException(org.apache.hadoop.hbase.DoNotRetryIOException) NotServingRegionException(org.apache.hadoop.hbase.NotServingRegionException) ScannerResetException(org.apache.hadoop.hbase.exceptions.ScannerResetException) TableNotEnabledException(org.apache.hadoop.hbase.TableNotEnabledException)

Example 4 with ScannerResetException

use of org.apache.hadoop.hbase.exceptions.ScannerResetException in project hbase by apache.

the class TestFromClientSideScanExcpetion method testScannerFailsAfterRetriesWhenCoprocessorThrowsIOE.

/**
 * Tests the case where a coprocessor throws a regular IOException in the scan. The expectation is
 * that the we will keep on retrying, but fail after the retries are exhausted instead of retrying
 * indefinitely.
 */
@Test
public void testScannerFailsAfterRetriesWhenCoprocessorThrowsIOE() throws IOException, InterruptedException {
    TableName tableName = TableName.valueOf(name.getMethodName());
    reset();
    // throw exceptions in every retry
    THROW_ONCE.set(false);
    try (Table t = TEST_UTIL.createTable(tableName, FAMILY)) {
        TEST_UTIL.loadTable(t, FAMILY, false);
        TEST_UTIL.getAdmin().flush(tableName);
        inject();
        TEST_UTIL.countRows(t, new Scan().addColumn(FAMILY, FAMILY));
        fail("Should have thrown an exception");
    } catch (ScannerResetException expected) {
    // expected
    } catch (RetriesExhaustedException e) {
        // expected
        assertThat(e.getCause(), instanceOf(ScannerResetException.class));
    }
    assertTrue(REQ_COUNT.get() >= 3);
}
Also used : TableName(org.apache.hadoop.hbase.TableName) ScannerResetException(org.apache.hadoop.hbase.exceptions.ScannerResetException) Test(org.junit.Test)

Example 5 with ScannerResetException

use of org.apache.hadoop.hbase.exceptions.ScannerResetException in project hbase by apache.

the class ScannerCallable method next.

private ScanResponse next() throws IOException {
    // Reset the heartbeat flag prior to each RPC in case an exception is thrown by the server
    setHeartbeatMessage(false);
    incRPCcallsMetrics();
    ScanRequest request = RequestConverter.buildScanRequest(scannerId, caching, false, nextCallSeq, this.scanMetrics != null, renew, scan.getLimit());
    try {
        ScanResponse response = getStub().scan(getRpcController(), request);
        nextCallSeq++;
        return response;
    } catch (Exception e) {
        IOException ioe = ProtobufUtil.handleRemoteException(e);
        if (logScannerActivity) {
            LOG.info("Got exception making request " + ProtobufUtil.toText(request) + " to " + getLocation(), e);
        }
        if (logScannerActivity) {
            if (ioe instanceof UnknownScannerException) {
                try {
                    HRegionLocation location = getConnection().relocateRegion(getTableName(), scan.getStartRow());
                    LOG.info("Scanner=" + scannerId + " expired, current region location is " + location.toString());
                } catch (Throwable t) {
                    LOG.info("Failed to relocate region", t);
                }
            } else if (ioe instanceof ScannerResetException) {
                LOG.info("Scanner=" + scannerId + " has received an exception, and the server " + "asked us to reset the scanner state.", ioe);
            }
        }
        // yeah and hard to follow and in need of a refactor).
        if (ioe instanceof NotServingRegionException) {
            // Attach NSRE to signal client that it needs to re-setup scanner.
            if (this.scanMetrics != null) {
                this.scanMetrics.countOfNSRE.incrementAndGet();
            }
            throw new DoNotRetryIOException("Resetting the scanner -- see exception cause", ioe);
        } else if (ioe instanceof RegionServerStoppedException) {
            // open scanner against new location.
            throw new DoNotRetryIOException("Resetting the scanner -- see exception cause", ioe);
        } else {
            // The outer layers will retry
            throw ioe;
        }
    }
}
Also used : ScanRequest(org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ScanRequest) RegionServerStoppedException(org.apache.hadoop.hbase.regionserver.RegionServerStoppedException) HRegionLocation(org.apache.hadoop.hbase.HRegionLocation) NotServingRegionException(org.apache.hadoop.hbase.NotServingRegionException) DoNotRetryIOException(org.apache.hadoop.hbase.DoNotRetryIOException) ScannerResetException(org.apache.hadoop.hbase.exceptions.ScannerResetException) ScanResponse(org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ScanResponse) InterruptedIOException(java.io.InterruptedIOException) DoNotRetryIOException(org.apache.hadoop.hbase.DoNotRetryIOException) IOException(java.io.IOException) HBaseIOException(org.apache.hadoop.hbase.HBaseIOException) InterruptedIOException(java.io.InterruptedIOException) NotServingRegionException(org.apache.hadoop.hbase.NotServingRegionException) DoNotRetryIOException(org.apache.hadoop.hbase.DoNotRetryIOException) IOException(java.io.IOException) UnknownHostException(java.net.UnknownHostException) RegionServerStoppedException(org.apache.hadoop.hbase.regionserver.RegionServerStoppedException) UnknownScannerException(org.apache.hadoop.hbase.UnknownScannerException) ScannerResetException(org.apache.hadoop.hbase.exceptions.ScannerResetException) HBaseIOException(org.apache.hadoop.hbase.HBaseIOException) UnknownScannerException(org.apache.hadoop.hbase.UnknownScannerException)

Aggregations

ScannerResetException (org.apache.hadoop.hbase.exceptions.ScannerResetException)5 DoNotRetryIOException (org.apache.hadoop.hbase.DoNotRetryIOException)4 TableName (org.apache.hadoop.hbase.TableName)3 IOException (java.io.IOException)2 HBaseIOException (org.apache.hadoop.hbase.HBaseIOException)2 NotServingRegionException (org.apache.hadoop.hbase.NotServingRegionException)2 UnknownScannerException (org.apache.hadoop.hbase.UnknownScannerException)2 ScanResponse (org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ScanResponse)2 Test (org.junit.Test)2 FileNotFoundException (java.io.FileNotFoundException)1 InterruptedIOException (java.io.InterruptedIOException)1 UncheckedIOException (java.io.UncheckedIOException)1 UnknownHostException (java.net.UnknownHostException)1 ArrayList (java.util.ArrayList)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1 MutableObject (org.apache.commons.lang3.mutable.MutableObject)1 HRegionLocation (org.apache.hadoop.hbase.HRegionLocation)1 HTableDescriptor (org.apache.hadoop.hbase.HTableDescriptor)1 TableNotEnabledException (org.apache.hadoop.hbase.TableNotEnabledException)1 TableNotFoundException (org.apache.hadoop.hbase.TableNotFoundException)1