Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 57783200CCA for ; Wed, 5 Jul 2017 04:08:51 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 566C31622BD; Wed, 5 Jul 2017 02:08:51 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 2734F1622BC for ; Wed, 5 Jul 2017 04:08:50 +0200 (CEST) Received: (qmail 93950 invoked by uid 500); 5 Jul 2017 02:08:48 -0000 Mailing-List: contact commits-help@hbase.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@hbase.apache.org Delivered-To: mailing list commits@hbase.apache.org Received: (qmail 93941 invoked by uid 99); 5 Jul 2017 02:08:48 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 05 Jul 2017 02:08:48 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 463B4E10F8; Wed, 5 Jul 2017 02:08:46 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: zghao@apache.org To: commits@hbase.apache.org Message-Id: <0e8c987447d0462c8602fc26a3e7a5cd@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: hbase git commit: HBASE-18297 Provide a AsyncAdminBuilder to create new AsyncAdmin instance Date: Wed, 5 Jul 2017 02:08:46 +0000 (UTC) archived-at: Wed, 05 Jul 2017 02:08:51 -0000 Repository: hbase Updated Branches: refs/heads/branch-2 29ec74936 -> 507f5fb84 HBASE-18297 Provide a AsyncAdminBuilder to create new AsyncAdmin instance Project: http://git-wip-us.apache.org/repos/asf/hbase/repo Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/507f5fb8 Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/507f5fb8 Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/507f5fb8 Branch: refs/heads/branch-2 Commit: 507f5fb84414a8f1a3364926ba3559fb2845e95b Parents: 29ec749 Author: Guanghao Zhang Authored: Wed Jul 5 09:46:52 2017 +0800 Committer: Guanghao Zhang Committed: Wed Jul 5 10:10:05 2017 +0800 ---------------------------------------------------------------------- .../hadoop/hbase/client/AsyncAdminBuilder.java | 93 ++++++++ .../hbase/client/AsyncAdminBuilderBase.java | 77 +++++++ .../hadoop/hbase/client/AsyncConnection.java | 43 +++- .../hbase/client/AsyncConnectionImpl.java | 19 +- .../hadoop/hbase/client/RawAsyncHBaseAdmin.java | 12 +- .../hbase/client/TestAsyncAdminBuilder.java | 214 +++++++++++++++++++ 6 files changed, 440 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hbase/blob/507f5fb8/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdminBuilder.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdminBuilder.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdminBuilder.java new file mode 100644 index 0000000..d706949 --- /dev/null +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdminBuilder.java @@ -0,0 +1,93 @@ +/** + * 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.client; + +import static org.apache.hadoop.hbase.client.ConnectionUtils.retries2Attempts; + +import java.util.concurrent.TimeUnit; + +import org.apache.hadoop.hbase.classification.InterfaceAudience; + +/** + * For creating {@link AsyncAdmin}. The implementation should have default configurations set before + * returning the builder to user. So users are free to only set the configs they care about to + * create a new AsyncAdmin instance. + */ +@InterfaceAudience.Public +public interface AsyncAdminBuilder { + + /** + * Set timeout for a whole admin operation. Operation timeout and max attempt times(or max retry + * times) are both limitations for retrying, we will stop retrying when we reach any of the + * limitations. + * @param timeout + * @param unit + * @return this for invocation chaining + */ + AsyncAdminBuilder setOperationTimeout(long timeout, TimeUnit unit); + + /** + * Set timeout for each rpc request. + * @param timeout + * @param unit + * @return this for invocation chaining + */ + AsyncAdminBuilder setRpcTimeout(long timeout, TimeUnit unit); + + /** + * Set the base pause time for retrying. We use an exponential policy to generate sleep time when + * retrying. + * @param timeout + * @param unit + * @return this for invocation chaining + */ + AsyncAdminBuilder setRetryPause(long timeout, TimeUnit unit); + + /** + * Set the max retry times for an admin operation. Usually it is the max attempt times minus 1. + * Operation timeout and max attempt times(or max retry times) are both limitations for retrying, + * we will stop retrying when we reach any of the limitations. + * @param maxRetries + * @return this for invocation chaining + */ + default AsyncAdminBuilder setMaxRetries(int maxRetries) { + return setMaxAttempts(retries2Attempts(maxRetries)); + } + + /** + * Set the max attempt times for an admin operation. Usually it is the max retry times plus 1. + * Operation timeout and max attempt times(or max retry times) are both limitations for retrying, + * we will stop retrying when we reach any of the limitations. + * @param maxAttempts + * @return this for invocation chaining + */ + AsyncAdminBuilder setMaxAttempts(int maxAttempts); + + /** + * Set the number of retries that are allowed before we start to log. + * @param startLogErrorsCnt + * @return this for invocation chaining + */ + AsyncAdminBuilder setStartLogErrorsCnt(int startLogErrorsCnt); + + /** + * Create a {@link AsyncAdmin} instance. + * @return a {@link AsyncAdmin} instance + */ + T build(); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hbase/blob/507f5fb8/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdminBuilderBase.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdminBuilderBase.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdminBuilderBase.java new file mode 100644 index 0000000..013e8d7 --- /dev/null +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdminBuilderBase.java @@ -0,0 +1,77 @@ +/** + * 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.client; + +import java.util.concurrent.TimeUnit; + +import org.apache.hadoop.hbase.classification.InterfaceAudience; + +/** + * Base class for all asynchronous admin builders. + */ +@InterfaceAudience.Private +abstract class AsyncAdminBuilderBase implements AsyncAdminBuilder { + + protected long rpcTimeoutNs; + + protected long operationTimeoutNs; + + protected long pauseNs; + + protected int maxAttempts; + + protected int startLogErrorsCnt; + + AsyncAdminBuilderBase(AsyncConnectionConfiguration connConf) { + this.rpcTimeoutNs = connConf.getRpcTimeoutNs(); + this.operationTimeoutNs = connConf.getOperationTimeoutNs(); + this.pauseNs = connConf.getPauseNs(); + this.maxAttempts = connConf.getMaxRetries(); + this.startLogErrorsCnt = connConf.getStartLogErrorsCnt(); + } + + @Override + public AsyncAdminBuilder setOperationTimeout(long timeout, TimeUnit unit) { + this.operationTimeoutNs = unit.toNanos(timeout); + return this; + } + + @Override + public AsyncAdminBuilder setRpcTimeout(long timeout, TimeUnit unit) { + this.rpcTimeoutNs = unit.toNanos(timeout); + return this; + } + + @Override + public AsyncAdminBuilder setRetryPause(long timeout, TimeUnit unit) { + this.pauseNs = unit.toNanos(timeout); + return this; + } + + @Override + public AsyncAdminBuilder setMaxAttempts(int maxAttempts) { + this.maxAttempts = maxAttempts; + return this; + } + + @Override + public AsyncAdminBuilder setStartLogErrorsCnt(int startLogErrorsCnt) { + this.startLogErrorsCnt = startLogErrorsCnt; + return this; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hbase/blob/507f5fb8/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncConnection.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncConnection.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncConnection.java index 22ed064..04ef78e 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncConnection.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncConnection.java @@ -96,17 +96,44 @@ public interface AsyncConnection extends Closeable { AsyncTableBuilder getTableBuilder(TableName tableName, ExecutorService pool); /** - * Retrieve an AsyncAdmin implementation to administer an HBase cluster. The returned - * {@code CompletableFuture} will be finished directly in the rpc framework's callback thread, so - * typically you should not do any time consuming work inside these methods. - * @return an AsyncAdmin instance for cluster administration + * Retrieve an {@link AsyncAdmin} implementation to administer an HBase cluster. + *

+ * The returned instance will use default configs. Use {@link #getAdminBuilder()} if you want to + * customize some configs. + *

+ * The admin operation's returned {@code CompletableFuture} will be finished directly in the rpc + * framework's callback thread, so typically you should not do any time consuming work inside + * these methods. + * @return an {@link AsyncAdmin} instance for cluster administration + */ + default AsyncAdmin getAdmin() { + return getAdminBuilder().build(); + } + + /** + * Returns an {@link AsyncAdminBuilder} for creating {@link AsyncAdmin}. + *

+ * The admin operation's returned {@code CompletableFuture} will be finished directly in the rpc + * framework's callback thread, so typically you should not do any time consuming work inside + * these methods. */ - AsyncAdmin getAdmin(); + AsyncAdminBuilder getAdminBuilder(); + + /** + * Retrieve an {@link AsyncAdmin} implementation to administer an HBase cluster. + *

+ * The returned instance will use default configs. Use {@link #getAdminBuilder(ExecutorService)} + * if you want to customize some configs. + * @param pool the thread pool to use for executing callback + * @return an {@link AsyncAdmin} instance for cluster administration + */ + default AsyncAdmin getAdmin(ExecutorService pool) { + return getAdminBuilder(pool).build(); + } /** - * Retrieve an AsyncAdmin implementation to administer an HBase cluster. + * Returns an {@link AsyncAdminBuilder} for creating {@link AsyncAdmin}. * @param pool the thread pool to use for executing callback - * @return an AsyncAdmin instance for cluster administration */ - AsyncAdmin getAdmin(ExecutorService pool); + AsyncAdminBuilder getAdminBuilder(ExecutorService pool); } http://git-wip-us.apache.org/repos/asf/hbase/blob/507f5fb8/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncConnectionImpl.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncConnectionImpl.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncConnectionImpl.java index c170bce..5dd40cc 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncConnectionImpl.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncConnectionImpl.java @@ -278,12 +278,23 @@ class AsyncConnectionImpl implements AsyncConnection { } @Override - public AsyncAdmin getAdmin() { - return new RawAsyncHBaseAdmin(this); + public AsyncAdminBuilder getAdminBuilder() { + return new AsyncAdminBuilderBase(connConf) { + @Override + public RawAsyncHBaseAdmin build() { + return new RawAsyncHBaseAdmin(AsyncConnectionImpl.this, this); + } + }; } @Override - public AsyncAdmin getAdmin(ExecutorService pool) { - return new AsyncHBaseAdmin(new RawAsyncHBaseAdmin(this), pool); + public AsyncAdminBuilder getAdminBuilder(ExecutorService pool) { + return new AsyncAdminBuilderBase(connConf) { + @Override + public AsyncHBaseAdmin build() { + RawAsyncHBaseAdmin rawAdmin = new RawAsyncHBaseAdmin(AsyncConnectionImpl.this, this); + return new AsyncHBaseAdmin(rawAdmin, pool); + } + }; } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hbase/blob/507f5fb8/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java index fcfdf93..179fd7d 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java @@ -212,14 +212,14 @@ public class RawAsyncHBaseAdmin implements AsyncAdmin { private final NonceGenerator ng; - RawAsyncHBaseAdmin(AsyncConnectionImpl connection) { + RawAsyncHBaseAdmin(AsyncConnectionImpl connection, AsyncAdminBuilderBase builder) { this.connection = connection; this.metaTable = connection.getRawTable(META_TABLE_NAME); - this.rpcTimeoutNs = connection.connConf.getRpcTimeoutNs(); - this.operationTimeoutNs = connection.connConf.getOperationTimeoutNs(); - this.pauseNs = connection.connConf.getPauseNs(); - this.maxAttempts = connection.connConf.getMaxRetries(); - this.startLogErrorsCnt = connection.connConf.getStartLogErrorsCnt(); + this.rpcTimeoutNs = builder.rpcTimeoutNs; + this.operationTimeoutNs = builder.operationTimeoutNs; + this.pauseNs = builder.pauseNs; + this.maxAttempts = builder.maxAttempts; + this.startLogErrorsCnt = builder.startLogErrorsCnt; this.ng = connection.getNonceGenerator(); } http://git-wip-us.apache.org/repos/asf/hbase/blob/507f5fb8/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAdminBuilder.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAdminBuilder.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAdminBuilder.java new file mode 100644 index 0000000..ea25ee4 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAdminBuilder.java @@ -0,0 +1,214 @@ +/** + * 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.client; + +import static org.apache.hadoop.hbase.client.AsyncProcess.START_LOG_ERRORS_AFTER_COUNT_KEY; +import static org.apache.hadoop.hbase.NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; +import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment; +import org.apache.hadoop.hbase.coprocessor.MasterObserver; +import org.apache.hadoop.hbase.coprocessor.ObserverContext; +import org.apache.hadoop.hbase.testclassification.ClientTests; +import org.apache.hadoop.hbase.testclassification.LargeTests; +import org.apache.hadoop.hbase.util.Threads; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +@Category({ LargeTests.class, ClientTests.class }) +public class TestAsyncAdminBuilder { + + private static final Log LOG = LogFactory.getLog(TestAsyncAdminBuilder.class); + private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); + private static AsyncConnection ASYNC_CONN; + + @Parameter + public Supplier> getAdminBuilder; + + private static AsyncAdminBuilder getRawAsyncAdminBuilder() { + return ASYNC_CONN.getAdminBuilder(); + } + + private static AsyncAdminBuilder getAsyncAdminBuilder() { + return ASYNC_CONN.getAdminBuilder(ForkJoinPool.commonPool()); + } + + @Parameters + public static List params() { + return Arrays.asList(new Supplier[] { TestAsyncAdminBuilder::getRawAsyncAdminBuilder }, + new Supplier[] { TestAsyncAdminBuilder::getAsyncAdminBuilder }); + } + + private static final int DEFAULT_RPC_TIMEOUT = 10000; + private static final int DEFAULT_OPERATION_TIMEOUT = 30000; + private static final int DEFAULT_RETRIES_NUMBER = 2; + + @Before + public void setUp() throws Exception { + TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_RPC_TIMEOUT_KEY, DEFAULT_RPC_TIMEOUT); + TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_OPERATION_TIMEOUT, + DEFAULT_OPERATION_TIMEOUT); + TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, + DEFAULT_RETRIES_NUMBER); + TEST_UTIL.getConfiguration().setInt(START_LOG_ERRORS_AFTER_COUNT_KEY, 0); + } + + @After + public void tearDown() throws Exception { + IOUtils.closeQuietly(ASYNC_CONN); + TEST_UTIL.shutdownMiniCluster(); + } + + @Test + public void testRpcTimeout() throws Exception { + TEST_UTIL.getConfiguration().set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, + TestRpcTimeoutCoprocessor.class.getName()); + TEST_UTIL.startMiniCluster(2); + ASYNC_CONN = ConnectionFactory.createAsyncConnection(TEST_UTIL.getConfiguration()).get(); + + try { + getAdminBuilder.get().setRpcTimeout(DEFAULT_RPC_TIMEOUT / 2, TimeUnit.MILLISECONDS).build() + .getNamespaceDescriptor(DEFAULT_NAMESPACE_NAME_STR).get(); + fail("We expect an exception here"); + } catch (Exception e) { + // expected + } + + try { + getAdminBuilder.get().setRpcTimeout(DEFAULT_RPC_TIMEOUT * 2, TimeUnit.MILLISECONDS).build() + .getNamespaceDescriptor(DEFAULT_NAMESPACE_NAME_STR).get(); + } catch (Exception e) { + fail("The Operation should succeed, unexpected exception: " + e.getMessage()); + } + } + + @Test + public void testOperationTimeout() throws Exception { + // set retry number to 100 to make sure that this test only be affected by operation timeout + TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 100); + TEST_UTIL.getConfiguration().set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, + TestOperationTimeoutCoprocessor.class.getName()); + TEST_UTIL.startMiniCluster(2); + ASYNC_CONN = ConnectionFactory.createAsyncConnection(TEST_UTIL.getConfiguration()).get(); + + try { + getAdminBuilder.get() + .setOperationTimeout(DEFAULT_OPERATION_TIMEOUT / 2, TimeUnit.MILLISECONDS).build() + .getNamespaceDescriptor(DEFAULT_NAMESPACE_NAME_STR).get(); + fail("We expect an exception here"); + } catch (Exception e) { + // expected + } + + try { + getAdminBuilder.get() + .setOperationTimeout(DEFAULT_OPERATION_TIMEOUT * 2, TimeUnit.MILLISECONDS).build() + .getNamespaceDescriptor(DEFAULT_NAMESPACE_NAME_STR).get(); + } catch (Exception e) { + fail("The Operation should succeed, unexpected exception: " + e.getMessage()); + } + } + + @Test + public void testMaxRetries() throws Exception { + // set operation timeout to 300s to make sure that this test only be affected by retry number + TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_OPERATION_TIMEOUT, 300000); + TEST_UTIL.getConfiguration().set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, + TestMaxRetriesCoprocessor.class.getName()); + TEST_UTIL.startMiniCluster(2); + ASYNC_CONN = ConnectionFactory.createAsyncConnection(TEST_UTIL.getConfiguration()).get(); + + try { + getAdminBuilder.get().setMaxRetries(DEFAULT_RETRIES_NUMBER / 2).build() + .getNamespaceDescriptor(DEFAULT_NAMESPACE_NAME_STR).get(); + fail("We expect an exception here"); + } catch (Exception e) { + // expected + } + + try { + getAdminBuilder.get().setMaxRetries(DEFAULT_RETRIES_NUMBER * 2).build() + .getNamespaceDescriptor(DEFAULT_NAMESPACE_NAME_STR).get(); + } catch (Exception e) { + fail("The Operation should succeed, unexpected exception: " + e.getMessage()); + } + } + + public static class TestRpcTimeoutCoprocessor implements MasterObserver { + public TestRpcTimeoutCoprocessor() { + } + + @Override + public void preGetNamespaceDescriptor(ObserverContext ctx, + String namespace) throws IOException { + Threads.sleep(DEFAULT_RPC_TIMEOUT); + } + } + + public static class TestOperationTimeoutCoprocessor implements MasterObserver { + AtomicLong sleepTime = new AtomicLong(0); + + public TestOperationTimeoutCoprocessor() { + } + + @Override + public void preGetNamespaceDescriptor(ObserverContext ctx, + String namespace) throws IOException { + Threads.sleep(DEFAULT_RPC_TIMEOUT / 2); + if (sleepTime.addAndGet(DEFAULT_RPC_TIMEOUT / 2) < DEFAULT_OPERATION_TIMEOUT) { + throw new IOException("call fail"); + } + } + } + + public static class TestMaxRetriesCoprocessor implements MasterObserver { + AtomicLong retryNum = new AtomicLong(0); + + public TestMaxRetriesCoprocessor() { + } + + @Override + public void preGetNamespaceDescriptor(ObserverContext ctx, + String namespace) throws IOException { + if (retryNum.getAndIncrement() < DEFAULT_RETRIES_NUMBER) { + throw new IOException("call fail"); + } + } + } +} \ No newline at end of file