001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.client; 019 020import static org.junit.Assert.fail; 021 022import java.io.IOException; 023import java.net.SocketTimeoutException; 024import org.apache.hadoop.hbase.TableName; 025import org.junit.Before; 026import org.junit.Test; 027import org.slf4j.Logger; 028import org.slf4j.LoggerFactory; 029 030/** 031 * Based class for testing operation timeout logic. 032 */ 033public abstract class AbstractTestCIOperationTimeout extends AbstractTestCITimeout { 034 035 private static final Logger LOG = LoggerFactory.getLogger(AbstractTestCIOperationTimeout.class); 036 037 private TableName tableName; 038 039 @Before 040 public void setUp() throws IOException { 041 tableName = TableName.valueOf(name.getMethodName()); 042 TableDescriptor htd = TableDescriptorBuilder.newBuilder(tableName) 043 .setCoprocessor(SleepAndFailFirstTime.class.getName()) 044 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAM_NAM)).build(); 045 TEST_UTIL.getAdmin().createTable(htd); 046 } 047 048 protected abstract void execute(Table table) throws IOException; 049 050 /** 051 * Test that an operation can fail if we read the global operation timeout, even if the individual 052 * timeout is fine. We do that with: 053 * <ul> 054 * <li>client side: an operation timeout of 30 seconds</li> 055 * <li>server side: we sleep 20 second at each attempt. The first work fails, the second one 056 * succeeds. But the client won't wait that much, because 20 + 20 > 30, so the client timed out 057 * when the server answers.</li> 058 * </ul> 059 */ 060 @Test 061 public void testOperationTimeout() throws IOException { 062 TableBuilder builder = 063 TEST_UTIL.getConnection().getTableBuilder(tableName, null).setRpcTimeout(Integer.MAX_VALUE) 064 .setReadRpcTimeout(Integer.MAX_VALUE).setWriteRpcTimeout(Integer.MAX_VALUE); 065 // Check that it works if the timeout is big enough 066 SleepAndFailFirstTime.ct.set(0); 067 try (Table table = builder.setOperationTimeout(120 * 1000).build()) { 068 execute(table); 069 } 070 // Resetting and retrying. Will fail this time, not enough time for the second try 071 SleepAndFailFirstTime.ct.set(0); 072 try (Table table = builder.setOperationTimeout(30 * 1000).build()) { 073 SleepAndFailFirstTime.ct.set(0); 074 execute(table); 075 fail("We expect an exception here"); 076 } catch (SocketTimeoutException | RetriesExhaustedException e) { 077 // The client has a CallTimeout class, but it's not shared. We're not very clean today, 078 // in the general case you can expect the call to stop, but the exception may vary. 079 // In this test however, we're sure that it will be a socket timeout. 080 LOG.info("We received an exception, as expected ", e); 081 } 082 } 083}