Repository: hbase Updated Branches: refs/heads/branch-1 35e4eb7a7 -> b123313f1
HBASE-17578 Thrift metrics should handle exceptions Project: http://git-wip-us.apache.org/repos/asf/hbase/repo Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/b123313f Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/b123313f Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/b123313f Branch: refs/heads/branch-1 Commit: b123313f11a35f545e435b74bf27ec50a58dbfbe Parents: 35e4eb7 Author: Gary Helmling <ga...@apache.org> Authored: Wed Dec 28 13:13:24 2016 -0800 Committer: Gary Helmling <ga...@apache.org> Committed: Mon Feb 6 12:20:19 2017 -0800 ---------------------------------------------------------------------- .../hbase/ipc/MetricsHBaseServerSource.java | 37 +----- .../hbase/metrics/ExceptionTrackingSource.java | 56 +++++++++ .../hbase/thrift/MetricsThriftServerSource.java | 5 +- .../hbase/ipc/MetricsHBaseServerSourceImpl.java | 85 +------------ .../metrics/ExceptionTrackingSourceImpl.java | 118 +++++++++++++++++++ .../thrift/MetricsThriftServerSourceImpl.java | 4 +- .../hbase/thrift/HbaseHandlerMetricsProxy.java | 9 +- .../hadoop/hbase/thrift/ThriftMetrics.java | 61 ++++++++++ .../hadoop/hbase/thrift/ThriftServerRunner.java | 102 +++++++++++----- .../thrift2/ThriftHBaseServiceHandler.java | 46 +++++++- .../hbase/thrift/ErrorThrowingGetObserver.java | 102 ++++++++++++++++ .../hadoop/hbase/thrift/TestThriftServer.java | 79 ++++++++++++- .../thrift2/TestThriftHBaseServiceHandler.java | 71 ++++++++++- 13 files changed, 611 insertions(+), 164 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hbase/blob/b123313f/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/ipc/MetricsHBaseServerSource.java ---------------------------------------------------------------------- diff --git a/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/ipc/MetricsHBaseServerSource.java b/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/ipc/MetricsHBaseServerSource.java index 8bee67e..6128c8f 100644 --- a/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/ipc/MetricsHBaseServerSource.java +++ b/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/ipc/MetricsHBaseServerSource.java @@ -19,9 +19,9 @@ package org.apache.hadoop.hbase.ipc; -import org.apache.hadoop.hbase.metrics.BaseSource; +import org.apache.hadoop.hbase.metrics.ExceptionTrackingSource; -public interface MetricsHBaseServerSource extends BaseSource { +public interface MetricsHBaseServerSource extends ExceptionTrackingSource { String AUTHORIZATION_SUCCESSES_NAME = "authorizationSuccesses"; String AUTHORIZATION_SUCCESSES_DESC = "Number of authorization successes."; @@ -86,22 +86,6 @@ public interface MetricsHBaseServerSource extends BaseSource { String NUM_LIFO_MODE_SWITCHES_DESC = "Total number of calls in general queue which " + "were served from the tail of the queue"; - String EXCEPTIONS_NAME="exceptions"; - String EXCEPTIONS_DESC="Exceptions caused by requests"; - String EXCEPTIONS_TYPE_DESC="Number of requests that resulted in the specified type of Exception"; - String EXCEPTIONS_OOO_NAME="exceptions.OutOfOrderScannerNextException"; - String EXCEPTIONS_BUSY_NAME="exceptions.RegionTooBusyException"; - String EXCEPTIONS_UNKNOWN_NAME="exceptions.UnknownScannerException"; - String EXCEPTIONS_SCANNER_RESET_NAME="exceptions.ScannerResetException"; - String EXCEPTIONS_SANITY_NAME="exceptions.FailedSanityCheckException"; - String EXCEPTIONS_MOVED_NAME="exceptions.RegionMovedException"; - String EXCEPTIONS_NSRE_NAME="exceptions.NotServingRegionException"; - String EXCEPTIONS_MULTI_TOO_LARGE_NAME = "exceptions.multiResponseTooLarge"; - String EXCEPTIONS_MULTI_TOO_LARGE_DESC = "A response to a multi request was too large and the " + - "rest of the requests will have to be retried."; - String EXCEPTIONS_CALL_QUEUE_TOO_BIG = "exceptions.callQueueTooBig"; - String EXCEPTIONS_CALL_QUEUE_TOO_BIG_DESC = "Call queue is full"; - void authorizationSuccess(); void authorizationFailure(); @@ -112,21 +96,6 @@ public interface MetricsHBaseServerSource extends BaseSource { void authenticationFallback(); - void exception(); - - /** - * Different types of exceptions - */ - void outOfOrderException(); - void failedSanityException(); - void movedRegionException(); - void notServingRegionException(); - void unknownScannerException(); - void scannerResetException(); - void tooBusyException(); - void multiActionTooLargeException(); - void callQueueTooBigException(); - void sentBytes(long count); void receivedBytes(int count); @@ -140,6 +109,4 @@ public interface MetricsHBaseServerSource extends BaseSource { void processedCall(int processingTime); void queuedAndProcessedCall(int totalTime); - - } http://git-wip-us.apache.org/repos/asf/hbase/blob/b123313f/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/metrics/ExceptionTrackingSource.java ---------------------------------------------------------------------- diff --git a/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/metrics/ExceptionTrackingSource.java b/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/metrics/ExceptionTrackingSource.java new file mode 100644 index 0000000..fa252fc --- /dev/null +++ b/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/metrics/ExceptionTrackingSource.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase.metrics; + +/** + * Common interface for metrics source implementations which need to track individual exception + * types thrown or received. + */ +public interface ExceptionTrackingSource extends BaseSource { + String EXCEPTIONS_NAME="exceptions"; + String EXCEPTIONS_DESC="Exceptions caused by requests"; + String EXCEPTIONS_TYPE_DESC="Number of requests that resulted in the specified type of Exception"; + String EXCEPTIONS_OOO_NAME="exceptions.OutOfOrderScannerNextException"; + String EXCEPTIONS_BUSY_NAME="exceptions.RegionTooBusyException"; + String EXCEPTIONS_UNKNOWN_NAME="exceptions.UnknownScannerException"; + String EXCEPTIONS_SCANNER_RESET_NAME="exceptions.ScannerResetException"; + String EXCEPTIONS_SANITY_NAME="exceptions.FailedSanityCheckException"; + String EXCEPTIONS_MOVED_NAME="exceptions.RegionMovedException"; + String EXCEPTIONS_NSRE_NAME="exceptions.NotServingRegionException"; + String EXCEPTIONS_MULTI_TOO_LARGE_NAME = "exceptions.multiResponseTooLarge"; + String EXCEPTIONS_MULTI_TOO_LARGE_DESC = "A response to a multi request was too large and the " + + "rest of the requests will have to be retried."; + String EXCEPTIONS_CALL_QUEUE_TOO_BIG = "exceptions.callQueueTooBig"; + String EXCEPTIONS_CALL_QUEUE_TOO_BIG_DESC = "Call queue is full"; + + void exception(); + + /** + * Different types of exceptions + */ + void outOfOrderException(); + void failedSanityException(); + void movedRegionException(); + void notServingRegionException(); + void unknownScannerException(); + void scannerResetException(); + void tooBusyException(); + void multiActionTooLargeException(); + void callQueueTooBigException(); +} http://git-wip-us.apache.org/repos/asf/hbase/blob/b123313f/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/thrift/MetricsThriftServerSource.java ---------------------------------------------------------------------- diff --git a/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/thrift/MetricsThriftServerSource.java b/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/thrift/MetricsThriftServerSource.java index 558a863..77fb11a 100644 --- a/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/thrift/MetricsThriftServerSource.java +++ b/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/thrift/MetricsThriftServerSource.java @@ -18,13 +18,13 @@ package org.apache.hadoop.hbase.thrift; -import org.apache.hadoop.hbase.metrics.BaseSource; +import org.apache.hadoop.hbase.metrics.ExceptionTrackingSource; import org.apache.hadoop.hbase.metrics.JvmPauseMonitorSource; /** * Interface of a class that will export metrics about Thrift to hadoop's metrics2. */ -public interface MetricsThriftServerSource extends BaseSource, JvmPauseMonitorSource { +public interface MetricsThriftServerSource extends ExceptionTrackingSource, JvmPauseMonitorSource { String BATCH_GET_KEY = "batchGet"; String BATCH_MUTATE_KEY = "batchMutate"; @@ -75,5 +75,4 @@ public interface MetricsThriftServerSource extends BaseSource, JvmPauseMonitorSo * @param time Time */ void incSlowCall(long time); - } http://git-wip-us.apache.org/repos/asf/hbase/blob/b123313f/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/ipc/MetricsHBaseServerSourceImpl.java ---------------------------------------------------------------------- diff --git a/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/ipc/MetricsHBaseServerSourceImpl.java b/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/ipc/MetricsHBaseServerSourceImpl.java index 69aa5fe..eee641a 100644 --- a/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/ipc/MetricsHBaseServerSourceImpl.java +++ b/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/ipc/MetricsHBaseServerSourceImpl.java @@ -21,6 +21,7 @@ package org.apache.hadoop.hbase.ipc; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.metrics.BaseSourceImpl; +import org.apache.hadoop.hbase.metrics.ExceptionTrackingSourceImpl; import org.apache.hadoop.hbase.metrics.Interns; import org.apache.hadoop.metrics2.MetricHistogram; import org.apache.hadoop.metrics2.MetricsCollector; @@ -28,7 +29,7 @@ import org.apache.hadoop.metrics2.MetricsRecordBuilder; import org.apache.hadoop.metrics2.lib.MutableFastCounter; @InterfaceAudience.Private -public class MetricsHBaseServerSourceImpl extends BaseSourceImpl +public class MetricsHBaseServerSourceImpl extends ExceptionTrackingSourceImpl implements MetricsHBaseServerSource { @@ -41,17 +42,6 @@ public class MetricsHBaseServerSourceImpl extends BaseSourceImpl private final MutableFastCounter sentBytes; private final MutableFastCounter receivedBytes; - private final MutableFastCounter exceptions; - private final MutableFastCounter exceptionsOOO; - private final MutableFastCounter exceptionsBusy; - private final MutableFastCounter exceptionsUnknown; - private final MutableFastCounter exceptionsScannerReset; - private final MutableFastCounter exceptionsSanity; - private final MutableFastCounter exceptionsNSRE; - private final MutableFastCounter exceptionsMoved; - private final MutableFastCounter exceptionsMultiTooLarge; - private final MutableFastCounter exceptionsCallQueueTooBig; - private MetricHistogram queueCallTime; private MetricHistogram processCallTime; @@ -71,27 +61,6 @@ public class MetricsHBaseServerSourceImpl extends BaseSourceImpl AUTHORIZATION_SUCCESSES_DESC, 0L); this.authorizationFailures = this.getMetricsRegistry().newCounter(AUTHORIZATION_FAILURES_NAME, AUTHORIZATION_FAILURES_DESC, 0L); - - this.exceptions = this.getMetricsRegistry().newCounter(EXCEPTIONS_NAME, EXCEPTIONS_DESC, 0L); - this.exceptionsOOO = this.getMetricsRegistry() - .newCounter(EXCEPTIONS_OOO_NAME, EXCEPTIONS_TYPE_DESC, 0L); - this.exceptionsBusy = this.getMetricsRegistry() - .newCounter(EXCEPTIONS_BUSY_NAME, EXCEPTIONS_TYPE_DESC, 0L); - this.exceptionsUnknown = this.getMetricsRegistry() - .newCounter(EXCEPTIONS_UNKNOWN_NAME, EXCEPTIONS_TYPE_DESC, 0L); - this.exceptionsScannerReset = this.getMetricsRegistry() - .newCounter(EXCEPTIONS_SCANNER_RESET_NAME, EXCEPTIONS_TYPE_DESC, 0L); - this.exceptionsSanity = this.getMetricsRegistry() - .newCounter(EXCEPTIONS_SANITY_NAME, EXCEPTIONS_TYPE_DESC, 0L); - this.exceptionsMoved = this.getMetricsRegistry() - .newCounter(EXCEPTIONS_MOVED_NAME, EXCEPTIONS_TYPE_DESC, 0L); - this.exceptionsNSRE = this.getMetricsRegistry() - .newCounter(EXCEPTIONS_NSRE_NAME, EXCEPTIONS_TYPE_DESC, 0L); - this.exceptionsMultiTooLarge = this.getMetricsRegistry() - .newCounter(EXCEPTIONS_MULTI_TOO_LARGE_NAME, EXCEPTIONS_MULTI_TOO_LARGE_DESC, 0L); - this.exceptionsCallQueueTooBig = this.getMetricsRegistry().newCounter( - EXCEPTIONS_CALL_QUEUE_TOO_BIG, EXCEPTIONS_CALL_QUEUE_TOO_BIG_DESC, 0L); - this.authenticationSuccesses = this.getMetricsRegistry().newCounter( AUTHENTICATION_SUCCESSES_NAME, AUTHENTICATION_SUCCESSES_DESC, 0L); this.authenticationFailures = this.getMetricsRegistry().newCounter(AUTHENTICATION_FAILURES_NAME, @@ -135,56 +104,6 @@ public class MetricsHBaseServerSourceImpl extends BaseSourceImpl } @Override - public void exception() { - exceptions.incr(); - } - - @Override - public void outOfOrderException() { - exceptionsOOO.incr(); - } - - @Override - public void failedSanityException() { - exceptionsSanity.incr(); - } - - @Override - public void movedRegionException() { - exceptionsMoved.incr(); - } - - @Override - public void notServingRegionException() { - exceptionsNSRE.incr(); - } - - @Override - public void unknownScannerException() { - exceptionsUnknown.incr(); - } - - @Override - public void scannerResetException() { - exceptionsScannerReset.incr(); - } - - @Override - public void tooBusyException() { - exceptionsBusy.incr(); - } - - @Override - public void multiActionTooLargeException() { - exceptionsMultiTooLarge.incr(); - } - - @Override - public void callQueueTooBigException() { - exceptionsCallQueueTooBig.incr(); - } - - @Override public void authenticationSuccess() { authenticationSuccesses.incr(); } http://git-wip-us.apache.org/repos/asf/hbase/blob/b123313f/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/metrics/ExceptionTrackingSourceImpl.java ---------------------------------------------------------------------- diff --git a/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/metrics/ExceptionTrackingSourceImpl.java b/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/metrics/ExceptionTrackingSourceImpl.java new file mode 100644 index 0000000..9ed61a1 --- /dev/null +++ b/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/metrics/ExceptionTrackingSourceImpl.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase.metrics; + +import org.apache.hadoop.metrics2.lib.MutableFastCounter; + +/** + * Common base implementation for metrics sources which need to track exceptions thrown or + * received. + */ +public class ExceptionTrackingSourceImpl extends BaseSourceImpl + implements ExceptionTrackingSource { + protected MutableFastCounter exceptions; + protected MutableFastCounter exceptionsOOO; + protected MutableFastCounter exceptionsBusy; + protected MutableFastCounter exceptionsUnknown; + protected MutableFastCounter exceptionsScannerReset; + protected MutableFastCounter exceptionsSanity; + protected MutableFastCounter exceptionsNSRE; + protected MutableFastCounter exceptionsMoved; + protected MutableFastCounter exceptionsMultiTooLarge; + protected MutableFastCounter exceptionsCallQueueTooBig; + + public ExceptionTrackingSourceImpl(String metricsName, String metricsDescription, + String metricsContext, String metricsJmxContext) { + super(metricsName, metricsDescription, metricsContext, metricsJmxContext); + } + + @Override + public void init() { + super.init(); + this.exceptions = this.getMetricsRegistry().newCounter(EXCEPTIONS_NAME, EXCEPTIONS_DESC, 0L); + this.exceptionsOOO = this.getMetricsRegistry() + .newCounter(EXCEPTIONS_OOO_NAME, EXCEPTIONS_TYPE_DESC, 0L); + this.exceptionsBusy = this.getMetricsRegistry() + .newCounter(EXCEPTIONS_BUSY_NAME, EXCEPTIONS_TYPE_DESC, 0L); + this.exceptionsUnknown = this.getMetricsRegistry() + .newCounter(EXCEPTIONS_UNKNOWN_NAME, EXCEPTIONS_TYPE_DESC, 0L); + this.exceptionsScannerReset = this.getMetricsRegistry() + .newCounter(EXCEPTIONS_SCANNER_RESET_NAME, EXCEPTIONS_TYPE_DESC, 0L); + this.exceptionsSanity = this.getMetricsRegistry() + .newCounter(EXCEPTIONS_SANITY_NAME, EXCEPTIONS_TYPE_DESC, 0L); + this.exceptionsMoved = this.getMetricsRegistry() + .newCounter(EXCEPTIONS_MOVED_NAME, EXCEPTIONS_TYPE_DESC, 0L); + this.exceptionsNSRE = this.getMetricsRegistry() + .newCounter(EXCEPTIONS_NSRE_NAME, EXCEPTIONS_TYPE_DESC, 0L); + this.exceptionsMultiTooLarge = this.getMetricsRegistry() + .newCounter(EXCEPTIONS_MULTI_TOO_LARGE_NAME, EXCEPTIONS_MULTI_TOO_LARGE_DESC, 0L); + this.exceptionsCallQueueTooBig = this.getMetricsRegistry() + .newCounter(EXCEPTIONS_CALL_QUEUE_TOO_BIG, EXCEPTIONS_CALL_QUEUE_TOO_BIG_DESC, 0L); + } + + @Override + public void exception() { + exceptions.incr(); + } + + @Override + public void outOfOrderException() { + exceptionsOOO.incr(); + } + + @Override + public void failedSanityException() { + exceptionsSanity.incr(); + } + + @Override + public void movedRegionException() { + exceptionsMoved.incr(); + } + + @Override + public void notServingRegionException() { + exceptionsNSRE.incr(); + } + + @Override + public void unknownScannerException() { + exceptionsUnknown.incr(); + } + + @Override + public void scannerResetException() { + exceptionsScannerReset.incr(); + } + + @Override + public void tooBusyException() { + exceptionsBusy.incr(); + } + + @Override + public void multiActionTooLargeException() { + exceptionsMultiTooLarge.incr(); + } + + @Override + public void callQueueTooBigException() { + exceptionsCallQueueTooBig.incr(); + } +} http://git-wip-us.apache.org/repos/asf/hbase/blob/b123313f/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/thrift/MetricsThriftServerSourceImpl.java ---------------------------------------------------------------------- diff --git a/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/thrift/MetricsThriftServerSourceImpl.java b/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/thrift/MetricsThriftServerSourceImpl.java index 71f67eb..27323ac 100644 --- a/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/thrift/MetricsThriftServerSourceImpl.java +++ b/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/thrift/MetricsThriftServerSourceImpl.java @@ -20,6 +20,7 @@ package org.apache.hadoop.hbase.thrift; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.metrics.BaseSourceImpl; +import org.apache.hadoop.hbase.metrics.ExceptionTrackingSourceImpl; import org.apache.hadoop.metrics2.MetricHistogram; import org.apache.hadoop.metrics2.lib.MutableFastCounter; import org.apache.hadoop.metrics2.lib.MutableGaugeLong; @@ -31,7 +32,7 @@ import org.apache.hadoop.metrics2.lib.MutableHistogram; * Implements BaseSource through BaseSourceImpl, following the pattern */ @InterfaceAudience.Private -public class MetricsThriftServerSourceImpl extends BaseSourceImpl implements +public class MetricsThriftServerSourceImpl extends ExceptionTrackingSourceImpl implements MetricsThriftServerSource { private MetricHistogram batchGetStat; @@ -73,7 +74,6 @@ public class MetricsThriftServerSourceImpl extends BaseSourceImpl implements thriftCallStat = getMetricsRegistry().newTimeHistogram(THRIFT_CALL_KEY); thriftSlowCallStat = getMetricsRegistry().newTimeHistogram(SLOW_THRIFT_CALL_KEY); callQueueLenGauge = getMetricsRegistry().getGauge(CALL_QUEUE_LEN_KEY, 0); - } @Override http://git-wip-us.apache.org/repos/asf/hbase/blob/b123313f/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HbaseHandlerMetricsProxy.java ---------------------------------------------------------------------- diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HbaseHandlerMetricsProxy.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HbaseHandlerMetricsProxy.java index 51a0444..794143d 100644 --- a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HbaseHandlerMetricsProxy.java +++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HbaseHandlerMetricsProxy.java @@ -62,16 +62,19 @@ public class HbaseHandlerMetricsProxy implements InvocationHandler { public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { Object result; + long start = now(); try { - long start = now(); result = m.invoke(handler, args); - long processTime = now() - start; - metrics.incMethodTime(m.getName(), processTime); } catch (InvocationTargetException e) { + metrics.exception(e.getCause()); throw e.getTargetException(); } catch (Exception e) { + metrics.exception(e); throw new RuntimeException( "unexpected invocation exception: " + e.getMessage()); + } finally { + long processTime = now() - start; + metrics.incMethodTime(m.getName(), processTime); } return result; } http://git-wip-us.apache.org/repos/asf/hbase/blob/b123313f/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftMetrics.java ---------------------------------------------------------------------- diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftMetrics.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftMetrics.java index 883bbdc..dc69b33 100644 --- a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftMetrics.java +++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftMetrics.java @@ -19,9 +19,21 @@ package org.apache.hadoop.hbase.thrift; +import org.apache.hadoop.hbase.CallQueueTooBigException; +import org.apache.hadoop.hbase.MultiActionResultTooLarge; +import org.apache.hadoop.hbase.NotServingRegionException; +import org.apache.hadoop.hbase.RegionTooBusyException; +import org.apache.hadoop.hbase.UnknownScannerException; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.CompatibilitySingletonFactory; +import org.apache.hadoop.hbase.exceptions.ClientExceptionsUtil; +import org.apache.hadoop.hbase.exceptions.FailedSanityCheckException; +import org.apache.hadoop.hbase.exceptions.OutOfOrderScannerNextException; +import org.apache.hadoop.hbase.exceptions.RegionMovedException; +import org.apache.hadoop.hbase.exceptions.ScannerResetException; +import org.apache.hadoop.hbase.thrift.generated.IOError; +import org.apache.hadoop.hbase.thrift2.generated.TIOError; /** * This class is for maintaining the various statistics of thrift server @@ -87,4 +99,53 @@ public class ThriftMetrics { } } + /** + * Increment the count for a specific exception type. This is called for each exception type + * that is returned to the thrift handler. + * @param rawThrowable type of exception + */ + public void exception(Throwable rawThrowable) { + source.exception(); + + Throwable throwable = unwrap(rawThrowable); + /** + * Keep some metrics for commonly seen exceptions + * + * Try and put the most common types first. + * Place child types before the parent type that they extend. + * + * If this gets much larger we might have to go to a hashmap + */ + if (throwable != null) { + if (throwable instanceof OutOfOrderScannerNextException) { + source.outOfOrderException(); + } else if (throwable instanceof RegionTooBusyException) { + source.tooBusyException(); + } else if (throwable instanceof UnknownScannerException) { + source.unknownScannerException(); + } else if (throwable instanceof ScannerResetException) { + source.scannerResetException(); + } else if (throwable instanceof RegionMovedException) { + source.movedRegionException(); + } else if (throwable instanceof NotServingRegionException) { + source.notServingRegionException(); + } else if (throwable instanceof FailedSanityCheckException) { + source.failedSanityException(); + } else if (throwable instanceof MultiActionResultTooLarge) { + source.multiActionTooLargeException(); + } else if (throwable instanceof CallQueueTooBigException) { + source.callQueueTooBigException(); + } + } + } + + private static Throwable unwrap(Throwable t) { + if (t == null) { + return t; + } + if (t instanceof TIOError || t instanceof IOError) { + t = t.getCause(); + } + return ClientExceptionsUtil.findException(t); + } } http://git-wip-us.apache.org/repos/asf/hbase/blob/b123313f/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java ---------------------------------------------------------------------- diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java index 5caf526..8ad387a 100644 --- a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java +++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java @@ -766,7 +766,7 @@ public class ThriftServerRunner implements Runnable { getAdmin().enableTable(getTableName(tableName)); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } } @@ -776,7 +776,7 @@ public class ThriftServerRunner implements Runnable { getAdmin().disableTable(getTableName(tableName)); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } } @@ -786,7 +786,7 @@ public class ThriftServerRunner implements Runnable { return this.connectionCache.getAdmin().isTableEnabled(getTableName(tableName)); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } } @@ -799,7 +799,7 @@ public class ThriftServerRunner implements Runnable { ((HBaseAdmin) getAdmin()).compact(getBytes(tableNameOrRegionName)); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } } @@ -812,7 +812,7 @@ public class ThriftServerRunner implements Runnable { ((HBaseAdmin) getAdmin()).majorCompact(getBytes(tableNameOrRegionName)); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } } @@ -827,7 +827,7 @@ public class ThriftServerRunner implements Runnable { return list; } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } } @@ -860,7 +860,7 @@ public class ThriftServerRunner implements Runnable { return Collections.emptyList(); } catch (IOException e){ LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } } @@ -905,7 +905,7 @@ public class ThriftServerRunner implements Runnable { return ThriftUtilities.cellFromHBase(result.rawCells()); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally { closeTable(table); } @@ -951,7 +951,7 @@ public class ThriftServerRunner implements Runnable { return ThriftUtilities.cellFromHBase(result.rawCells()); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally{ closeTable(table); } @@ -998,7 +998,7 @@ public class ThriftServerRunner implements Runnable { return ThriftUtilities.cellFromHBase(result.rawCells()); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally{ closeTable(table); } @@ -1059,7 +1059,7 @@ public class ThriftServerRunner implements Runnable { return ThriftUtilities.rowResultFromHBase(result); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally{ closeTable(table); } @@ -1128,7 +1128,7 @@ public class ThriftServerRunner implements Runnable { return ThriftUtilities.rowResultFromHBase(result); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally{ closeTable(table); } @@ -1163,7 +1163,7 @@ public class ThriftServerRunner implements Runnable { } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally { closeTable(table); } @@ -1188,7 +1188,7 @@ public class ThriftServerRunner implements Runnable { table.delete(delete); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally { closeTable(table); } @@ -1211,7 +1211,7 @@ public class ThriftServerRunner implements Runnable { getAdmin().createTable(desc); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } catch (IllegalArgumentException e) { LOG.warn(e.getMessage(), e); throw new IllegalArgument(Throwables.getStackTraceAsString(e)); @@ -1235,7 +1235,7 @@ public class ThriftServerRunner implements Runnable { getAdmin().deleteTable(tableName); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } } @@ -1293,7 +1293,7 @@ public class ThriftServerRunner implements Runnable { table.put(put); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } catch (IllegalArgumentException e) { LOG.warn(e.getMessage(), e); throw new IllegalArgument(Throwables.getStackTraceAsString(e)); @@ -1366,7 +1366,7 @@ public class ThriftServerRunner implements Runnable { } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } catch (IllegalArgumentException e) { LOG.warn(e.getMessage(), e); throw new IllegalArgument(Throwables.getStackTraceAsString(e)); @@ -1396,7 +1396,7 @@ public class ThriftServerRunner implements Runnable { getBytes(row), family, qualifier, amount); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally { closeTable(table); } @@ -1434,7 +1434,7 @@ public class ThriftServerRunner implements Runnable { } } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } return ThriftUtilities.rowResultFromHBase(results, resultScannerWrapper.isColumnSorted()); } @@ -1493,7 +1493,7 @@ public class ThriftServerRunner implements Runnable { return addScanner(table.getScanner(scan), tScan.sortColumns); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally{ closeTable(table); } @@ -1522,7 +1522,7 @@ public class ThriftServerRunner implements Runnable { return addScanner(table.getScanner(scan), false); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally{ closeTable(table); } @@ -1552,7 +1552,7 @@ public class ThriftServerRunner implements Runnable { return addScanner(table.getScanner(scan), false); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally{ closeTable(table); } @@ -1586,7 +1586,7 @@ public class ThriftServerRunner implements Runnable { return addScanner(table.getScanner(scan), false); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally{ closeTable(table); } @@ -1616,7 +1616,7 @@ public class ThriftServerRunner implements Runnable { return addScanner(table.getScanner(scan), false); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally{ closeTable(table); } @@ -1648,7 +1648,7 @@ public class ThriftServerRunner implements Runnable { return addScanner(table.getScanner(scan), false); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally{ closeTable(table); } @@ -1673,7 +1673,7 @@ public class ThriftServerRunner implements Runnable { return columns; } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally { closeTable(table); } @@ -1688,7 +1688,7 @@ public class ThriftServerRunner implements Runnable { return ThriftUtilities.cellFromHBase(result.rawCells()); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } } @@ -1727,7 +1727,7 @@ public class ThriftServerRunner implements Runnable { return region; } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } } @@ -1781,7 +1781,7 @@ public class ThriftServerRunner implements Runnable { table.increment(inc); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally{ closeTable(table); } @@ -1812,7 +1812,7 @@ public class ThriftServerRunner implements Runnable { return ThriftUtilities.cellFromHBase(result.rawCells()); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } finally{ closeTable(table); } @@ -1846,7 +1846,7 @@ public class ThriftServerRunner implements Runnable { value != null ? getBytes(value) : HConstants.EMPTY_BYTE_ARRAY, put); } catch (IOException e) { LOG.warn(e.getMessage(), e); - throw new IOError(Throwables.getStackTraceAsString(e)); + throw getIOError(e); } catch (IllegalArgumentException e) { LOG.warn(e.getMessage(), e); throw new IllegalArgument(Throwables.getStackTraceAsString(e)); @@ -1857,6 +1857,11 @@ public class ThriftServerRunner implements Runnable { } + private static IOError getIOError(Throwable throwable) { + IOError error = new IOErrorWithCause(throwable); + error.setMessage(Throwables.getStackTraceAsString(throwable)); + return error; + } /** * Adds all the attributes into the Operation object @@ -1886,4 +1891,37 @@ public class ThriftServerRunner implements Runnable { } } } + + public static class IOErrorWithCause extends IOError { + private Throwable cause; + public IOErrorWithCause(Throwable cause) { + this.cause = cause; + } + + @Override + public Throwable getCause() { + return cause; + } + + @Override + public boolean equals(Object other) { + if (super.equals(other) && + other instanceof IOErrorWithCause) { + Throwable otherCause = ((IOErrorWithCause) other).getCause(); + if (this.getCause() != null) { + return otherCause != null && this.getCause().equals(otherCause); + } else { + return otherCause == null; + } + } + return false; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (cause != null ? cause.hashCode() : 0); + return result; + } + } } http://git-wip-us.apache.org/repos/asf/hbase/blob/b123313f/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/ThriftHBaseServiceHandler.java ---------------------------------------------------------------------- diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/ThriftHBaseServiceHandler.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/ThriftHBaseServiceHandler.java index 5900952..3cd8e95 100644 --- a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/ThriftHBaseServiceHandler.java +++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/ThriftHBaseServiceHandler.java @@ -111,16 +111,54 @@ public class ThriftHBaseServiceHandler implements THBaseService.Iface { @Override public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { Object result; + long start = now(); try { - long start = now(); result = m.invoke(handler, args); - int processTime = (int) (now() - start); - metrics.incMethodTime(m.getName(), processTime); } catch (InvocationTargetException e) { + metrics.exception(e.getCause()); throw e.getTargetException(); } catch (Exception e) { + metrics.exception(e); throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); + } finally { + int processTime = (int) (now() - start); + metrics.incMethodTime(m.getName(), processTime); + } + return result; + } + } + + private static class TIOErrorWithCause extends TIOError { + private Throwable cause; + + public TIOErrorWithCause(Throwable cause) { + super(); + this.cause = cause; + } + + @Override + public Throwable getCause() { + return cause; + } + + @Override + public boolean equals(Object other) { + if (super.equals(other) && + other instanceof TIOErrorWithCause) { + Throwable otherCause = ((TIOErrorWithCause) other).getCause(); + if (this.getCause() != null) { + return otherCause != null && this.getCause().equals(otherCause); + } else { + return otherCause == null; + } } + return false; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (cause != null ? cause.hashCode() : 0); return result; } } @@ -162,7 +200,7 @@ public class ThriftHBaseServiceHandler implements THBaseService.Iface { } private TIOError getTIOError(IOException e) { - TIOError err = new TIOError(); + TIOError err = new TIOErrorWithCause(e); err.setMessage(e.getMessage()); return err; } http://git-wip-us.apache.org/repos/asf/hbase/blob/b123313f/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/ErrorThrowingGetObserver.java ---------------------------------------------------------------------- diff --git a/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/ErrorThrowingGetObserver.java b/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/ErrorThrowingGetObserver.java new file mode 100644 index 0000000..810dabc --- /dev/null +++ b/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/ErrorThrowingGetObserver.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase.thrift; + +import org.apache.hadoop.hbase.CallQueueTooBigException; +import org.apache.hadoop.hbase.Cell; +import org.apache.hadoop.hbase.DoNotRetryIOException; +import org.apache.hadoop.hbase.MultiActionResultTooLarge; +import org.apache.hadoop.hbase.NotServingRegionException; +import org.apache.hadoop.hbase.RegionTooBusyException; +import org.apache.hadoop.hbase.UnknownScannerException; +import org.apache.hadoop.hbase.client.Get; +import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver; +import org.apache.hadoop.hbase.coprocessor.ObserverContext; +import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment; +import org.apache.hadoop.hbase.exceptions.FailedSanityCheckException; +import org.apache.hadoop.hbase.exceptions.OutOfOrderScannerNextException; +import org.apache.hadoop.hbase.exceptions.RegionMovedException; +import org.apache.hadoop.hbase.exceptions.ScannerResetException; +import org.apache.hadoop.hbase.metrics.ExceptionTrackingSource; +import org.apache.hadoop.hbase.util.Bytes; + +import java.io.IOException; +import java.util.List; + +/** + * Simple test coprocessor for injecting exceptions on Get requests. + */ +public class ErrorThrowingGetObserver extends BaseRegionObserver { + public static final String SHOULD_ERROR_ATTRIBUTE = "error"; + + @Override + public void preGetOp(ObserverContext<RegionCoprocessorEnvironment> e, + Get get, List<Cell> results) throws IOException { + byte[] errorType = get.getAttribute(SHOULD_ERROR_ATTRIBUTE); + if (errorType != null) { + ErrorType type = ErrorType.valueOf(Bytes.toString(errorType)); + switch (type) { + case CALL_QUEUE_TOO_BIG: + throw new CallQueueTooBigException("Failing for test"); + case MULTI_ACTION_RESULT_TOO_LARGE: + throw new MultiActionResultTooLarge("Failing for test"); + case FAILED_SANITY_CHECK: + throw new FailedSanityCheckException("Failing for test"); + case NOT_SERVING_REGION: + throw new NotServingRegionException("Failing for test"); + case REGION_MOVED: + throw new RegionMovedException( + e.getEnvironment().getRegionServerServices().getServerName(), 1); + case SCANNER_RESET: + throw new ScannerResetException("Failing for test"); + case UNKNOWN_SCANNER: + throw new UnknownScannerException("Failing for test"); + case REGION_TOO_BUSY: + throw new RegionTooBusyException("Failing for test"); + case OUT_OF_ORDER_SCANNER_NEXT: + throw new OutOfOrderScannerNextException("Failing for test"); + default: + throw new DoNotRetryIOException("Failing for test"); + } + } + super.preGetOp(e, get, results); + } + + public enum ErrorType { + CALL_QUEUE_TOO_BIG(ExceptionTrackingSource.EXCEPTIONS_CALL_QUEUE_TOO_BIG), + MULTI_ACTION_RESULT_TOO_LARGE(ExceptionTrackingSource.EXCEPTIONS_MULTI_TOO_LARGE_NAME), + FAILED_SANITY_CHECK(ExceptionTrackingSource.EXCEPTIONS_SANITY_NAME), + NOT_SERVING_REGION(ExceptionTrackingSource.EXCEPTIONS_NSRE_NAME), + REGION_MOVED(ExceptionTrackingSource.EXCEPTIONS_MOVED_NAME), + SCANNER_RESET(ExceptionTrackingSource.EXCEPTIONS_SCANNER_RESET_NAME), + UNKNOWN_SCANNER(ExceptionTrackingSource.EXCEPTIONS_UNKNOWN_NAME), + REGION_TOO_BUSY(ExceptionTrackingSource.EXCEPTIONS_BUSY_NAME), + OUT_OF_ORDER_SCANNER_NEXT(ExceptionTrackingSource.EXCEPTIONS_OOO_NAME); + + private final String metricName; + + ErrorType(String metricName) { + this.metricName = metricName; + } + + public String getMetricName() { + return metricName; + } + } +} http://git-wip-us.apache.org/repos/asf/hbase/blob/b123313f/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java ---------------------------------------------------------------------- diff --git a/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java b/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java index 5d12d04..48f9f22 100644 --- a/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java +++ b/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java @@ -22,10 +22,13 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -34,13 +37,17 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.CompatibilityFactory; import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionInfo; -import org.apache.hadoop.hbase.testclassification.LargeTests; +import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.filter.ParseFilter; import org.apache.hadoop.hbase.security.UserProvider; import org.apache.hadoop.hbase.test.MetricsAssertHelper; +import org.apache.hadoop.hbase.testclassification.LargeTests; import org.apache.hadoop.hbase.thrift.ThriftServerRunner.HBaseHandler; import org.apache.hadoop.hbase.thrift.generated.BatchMutation; import org.apache.hadoop.hbase.thrift.generated.ColumnDescriptor; @@ -97,6 +104,7 @@ public class TestThriftServer { public static void beforeClass() throws Exception { UTIL.getConfiguration().setBoolean(ThriftServerRunner.COALESCE_INC_KEY, true); UTIL.getConfiguration().setBoolean("hbase.table.sanity.checks", false); + UTIL.getConfiguration().setInt("hbase.client.retries.number", 3); UTIL.startMiniCluster(); } @@ -707,6 +715,75 @@ public class TestThriftServer { } } + @Test + public void testMetricsWithException() throws Exception { + String rowkey = "row1"; + String family = "f"; + String col = "c"; + // create a table which will throw exceptions for requests + TableName tableName = TableName.valueOf("testMetricsWithException"); + HTableDescriptor tableDesc = new HTableDescriptor(tableName); + tableDesc.addCoprocessor(ErrorThrowingGetObserver.class.getName()); + tableDesc.addFamily(new HColumnDescriptor(family)); + + Table table = UTIL.createTable(tableDesc, null); + long now = System.currentTimeMillis(); + table.put(new Put(Bytes.toBytes(rowkey)) + .addColumn(Bytes.toBytes(family), Bytes.toBytes(col), now, Bytes.toBytes("val1"))); + + Configuration conf = UTIL.getConfiguration(); + ThriftMetrics metrics = getMetrics(conf); + ThriftServerRunner.HBaseHandler hbaseHandler = + new ThriftServerRunner.HBaseHandler(UTIL.getConfiguration(), + UserProvider.instantiate(UTIL.getConfiguration())); + Hbase.Iface handler = HbaseHandlerMetricsProxy.newInstance(hbaseHandler, metrics, conf); + + ByteBuffer tTableName = asByteBuffer(tableName.getNameAsString()); + + // check metrics increment with a successful get + long preGetCounter = metricsHelper.checkCounterExists("getRow_num_ops", metrics.getSource()) ? + metricsHelper.getCounter("getRow_num_ops", metrics.getSource()) : + 0; + List<TRowResult> tRowResult = handler.getRow(tTableName, asByteBuffer(rowkey), null); + assertEquals(1, tRowResult.size()); + TRowResult tResult = tRowResult.get(0); + + TCell expectedColumnValue = new TCell(asByteBuffer("val1"), now); + + assertArrayEquals(Bytes.toBytes(rowkey), tResult.getRow()); + Collection<TCell> returnedColumnValues = tResult.getColumns().values(); + assertEquals(1, returnedColumnValues.size()); + assertEquals(expectedColumnValue, returnedColumnValues.iterator().next()); + + metricsHelper.assertCounter("getRow_num_ops", preGetCounter + 1, metrics.getSource()); + + // check metrics increment when the get throws each exception type + for (ErrorThrowingGetObserver.ErrorType type : ErrorThrowingGetObserver.ErrorType.values()) { + testExceptionType(handler, metrics, tTableName, rowkey, type); + } + } + + private void testExceptionType(Hbase.Iface handler, ThriftMetrics metrics, + ByteBuffer tTableName, String rowkey, + ErrorThrowingGetObserver.ErrorType errorType) throws Exception { + long preGetCounter = metricsHelper.getCounter("getRow_num_ops", metrics.getSource()); + String exceptionKey = errorType.getMetricName(); + long preExceptionCounter = metricsHelper.checkCounterExists(exceptionKey, metrics.getSource()) ? + metricsHelper.getCounter(exceptionKey, metrics.getSource()) : + 0; + Map<ByteBuffer, ByteBuffer> attributes = new HashMap<>(); + attributes.put(asByteBuffer(ErrorThrowingGetObserver.SHOULD_ERROR_ATTRIBUTE), + asByteBuffer(errorType.name())); + try { + List<TRowResult> tRowResult = handler.getRow(tTableName, asByteBuffer(rowkey), attributes); + fail("Get with error attribute should have thrown an exception"); + } catch (IOError e) { + LOG.info("Received exception: ", e); + metricsHelper.assertCounter("getRow_num_ops", preGetCounter + 1, metrics.getSource()); + metricsHelper.assertCounter(exceptionKey, preExceptionCounter + 1, metrics.getSource()); + } + } + /** * * @return a List of ColumnDescriptors for use in creating a table. Has one http://git-wip-us.apache.org/repos/asf/hbase/blob/b123313f/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift2/TestThriftHBaseServiceHandler.java ---------------------------------------------------------------------- diff --git a/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift2/TestThriftHBaseServiceHandler.java b/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift2/TestThriftHBaseServiceHandler.java index 2a59b87..4115b61 100644 --- a/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift2/TestThriftHBaseServiceHandler.java +++ b/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift2/TestThriftHBaseServiceHandler.java @@ -18,6 +18,7 @@ */ package org.apache.hadoop.hbase.thrift2; +import com.google.common.collect.Lists; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; @@ -25,7 +26,6 @@ import org.apache.hadoop.hbase.CompatibilityFactory; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HTableDescriptor; -import org.apache.hadoop.hbase.testclassification.MediumTests; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Admin; import org.apache.hadoop.hbase.client.Get; @@ -35,9 +35,12 @@ import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.client.Increment; import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Durability; +import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.filter.ParseFilter; import org.apache.hadoop.hbase.security.UserProvider; import org.apache.hadoop.hbase.test.MetricsAssertHelper; +import org.apache.hadoop.hbase.testclassification.MediumTests; +import org.apache.hadoop.hbase.thrift.ErrorThrowingGetObserver; import org.apache.hadoop.hbase.thrift.ThriftMetrics; import org.apache.hadoop.hbase.thrift2.generated.TAppend; import org.apache.hadoop.hbase.thrift2.generated.TColumn; @@ -139,6 +142,7 @@ public class TestThriftHBaseServiceHandler { @BeforeClass public static void beforeClass() throws Exception { + UTIL.getConfiguration().set("hbase.client.retries.number", "3"); UTIL.startMiniCluster(); Admin admin = new HBaseAdmin(UTIL.getConfiguration()); HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(tableAname)); @@ -976,6 +980,71 @@ public class TestThriftHBaseServiceHandler { } @Test + public void testMetricsWithException() throws Exception { + byte[] rowkey = Bytes.toBytes("row1"); + byte[] family = Bytes.toBytes("f"); + byte[] col = Bytes.toBytes("c"); + // create a table which will throw exceptions for requests + TableName tableName = TableName.valueOf("testMetricsWithException"); + HTableDescriptor tableDesc = new HTableDescriptor(tableName); + tableDesc.addCoprocessor(ErrorThrowingGetObserver.class.getName()); + tableDesc.addFamily(new HColumnDescriptor(family)); + + Table table = UTIL.createTable(tableDesc, null); + table.put(new Put(rowkey).addColumn(family, col, Bytes.toBytes("val1"))); + + ThriftHBaseServiceHandler hbaseHandler = createHandler(); + ThriftMetrics metrics = getMetrics(UTIL.getConfiguration()); + THBaseService.Iface handler = + ThriftHBaseServiceHandler.newInstance(hbaseHandler, metrics); + ByteBuffer tTableName = wrap(tableName.getName()); + + // check metrics increment with a successful get + long preGetCounter = metricsHelper.checkCounterExists("get_num_ops", metrics.getSource()) ? + metricsHelper.getCounter("get_num_ops", metrics.getSource()) : + 0; + TGet tGet = new TGet(wrap(rowkey)); + TResult tResult = handler.get(tTableName, tGet); + + List<TColumnValue> expectedColumnValues = Lists.newArrayList( + new TColumnValue(wrap(family), wrap(col), wrap(Bytes.toBytes("val1"))) + ); + assertArrayEquals(rowkey, tResult.getRow()); + List<TColumnValue> returnedColumnValues = tResult.getColumnValues(); + assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues); + + metricsHelper.assertCounter("get_num_ops", preGetCounter + 1, metrics.getSource()); + + // check metrics increment when the get throws each exception type + for (ErrorThrowingGetObserver.ErrorType type : ErrorThrowingGetObserver.ErrorType.values()) { + testExceptionType(handler, metrics, tTableName, rowkey, type); + } + } + + private void testExceptionType(THBaseService.Iface handler, ThriftMetrics metrics, + ByteBuffer tTableName, byte[] rowkey, ErrorThrowingGetObserver.ErrorType errorType) { + long preGetCounter = metricsHelper.getCounter("get_num_ops", metrics.getSource()); + String exceptionKey = errorType.getMetricName(); + long preExceptionCounter = metricsHelper.checkCounterExists(exceptionKey, metrics.getSource()) ? + metricsHelper.getCounter(exceptionKey, metrics.getSource()) : + 0; + TGet tGet = new TGet(wrap(rowkey)); + Map<ByteBuffer, ByteBuffer> attributes = new HashMap<>(); + attributes.put(wrap(Bytes.toBytes(ErrorThrowingGetObserver.SHOULD_ERROR_ATTRIBUTE)), + wrap(Bytes.toBytes(errorType.name()))); + tGet.setAttributes(attributes); + try { + TResult tResult = handler.get(tTableName, tGet); + fail("Get with error attribute should have thrown an exception"); + } catch (TException e) { + LOG.info("Received exception: ", e); + metricsHelper.assertCounter("get_num_ops", preGetCounter + 1, metrics.getSource()); + metricsHelper.assertCounter(exceptionKey, preExceptionCounter + 1, metrics.getSource()); + } + + } + + @Test public void testAttribute() throws Exception { byte[] rowName = "testAttribute".getBytes(); byte[] attributeKey = "attribute1".getBytes();