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 java.io.IOException;
021import java.util.List;
022import java.util.Optional;
023import org.apache.hadoop.hbase.Cell;
024import org.apache.hadoop.hbase.DoNotRetryIOException;
025import org.apache.hadoop.hbase.HBaseClassTestRule;
026import org.apache.hadoop.hbase.HBaseTestingUtility;
027import org.apache.hadoop.hbase.HConstants;
028import org.apache.hadoop.hbase.TableName;
029import org.apache.hadoop.hbase.coprocessor.ObserverContext;
030import org.apache.hadoop.hbase.coprocessor.RegionCoprocessor;
031import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
032import org.apache.hadoop.hbase.coprocessor.RegionObserver;
033import org.apache.hadoop.hbase.testclassification.ClientTests;
034import org.apache.hadoop.hbase.testclassification.MediumTests;
035import org.apache.hadoop.hbase.util.Bytes;
036import org.apache.hadoop.hbase.wal.WALEdit;
037import org.junit.AfterClass;
038import org.junit.BeforeClass;
039import org.junit.ClassRule;
040import org.junit.Test;
041import org.junit.experimental.categories.Category;
042
043@Category({ MediumTests.class, ClientTests.class })
044public class TestTableOperationException {
045
046  @ClassRule
047  public static final HBaseClassTestRule CLASS_RULE =
048    HBaseClassTestRule.forClass(TestTableOperationException.class);
049
050  private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
051
052  private static TableName TABLE_DONOT_RETRY = TableName.valueOf("TableDoNotRetry");
053
054  private static TableName TABLE_RETRY = TableName.valueOf("TableRetry");
055
056  private static Table tableDoNotRetry;
057
058  private static Table tableRetry;
059
060  private static byte[] CF = Bytes.toBytes("cf");
061
062  private static byte[] CQ = Bytes.toBytes("cq");
063
064  @BeforeClass
065  public static void setUp() throws Exception {
066    UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 2);
067    UTIL.startMiniCluster();
068    UTIL.getAdmin()
069      .createTable(TableDescriptorBuilder.newBuilder(TABLE_DONOT_RETRY)
070        .setCoprocessor(ThrowDoNotRetryIOExceptionCoprocessor.class.getName())
071        .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(CF).build()).build());
072    UTIL.getAdmin()
073      .createTable(TableDescriptorBuilder.newBuilder(TABLE_RETRY)
074        .setCoprocessor(ThrowIOExceptionCoprocessor.class.getName())
075        .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(CF).build()).build());
076    tableDoNotRetry = UTIL.getConnection().getTable(TABLE_DONOT_RETRY);
077    tableRetry = UTIL.getConnection().getTable(TABLE_RETRY);
078  }
079
080  @AfterClass
081  public static void tearDown() throws Exception {
082    UTIL.getAdmin().disableTable(TABLE_DONOT_RETRY);
083    UTIL.getAdmin().disableTable(TABLE_RETRY);
084    UTIL.getAdmin().deleteTable(TABLE_DONOT_RETRY);
085    UTIL.getAdmin().deleteTable(TABLE_RETRY);
086    UTIL.shutdownMiniCluster();
087  }
088
089  @Test(expected = DoNotRetryIOException.class)
090  public void testGetWithDoNotRetryIOException() throws Exception {
091    tableDoNotRetry.get(new Get(Bytes.toBytes("row")).addColumn(CF, CQ));
092  }
093
094  @Test(expected = DoNotRetryIOException.class)
095  public void testPutWithDoNotRetryIOException() throws Exception {
096    tableDoNotRetry.put(new Put(Bytes.toBytes("row")).addColumn(CF, CQ, Bytes.toBytes("value")));
097  }
098
099  @Test(expected = DoNotRetryIOException.class)
100  public void testDeleteWithDoNotRetryIOException() throws Exception {
101    tableDoNotRetry.delete(new Delete(Bytes.toBytes("row")).addColumn(CF, CQ));
102  }
103
104  @Test(expected = DoNotRetryIOException.class)
105  public void testAppendWithDoNotRetryIOException() throws Exception {
106    tableDoNotRetry
107      .append(new Append(Bytes.toBytes("row")).addColumn(CF, CQ, Bytes.toBytes("value")));
108  }
109
110  @Test(expected = DoNotRetryIOException.class)
111  public void testIncrementWithDoNotRetryIOException() throws Exception {
112    tableDoNotRetry.increment(new Increment(Bytes.toBytes("row")).addColumn(CF, CQ, 1));
113  }
114
115  @Test(expected = RetriesExhaustedException.class)
116  public void testGetWithIOException() throws Exception {
117    tableRetry.get(new Get(Bytes.toBytes("row")).addColumn(CF, CQ));
118  }
119
120  @Test(expected = RetriesExhaustedException.class)
121  public void testPutWithIOException() throws Exception {
122    tableRetry.put(new Put(Bytes.toBytes("row")).addColumn(CF, CQ, Bytes.toBytes("value")));
123  }
124
125  @Test(expected = RetriesExhaustedException.class)
126  public void testDeleteWithIOException() throws Exception {
127    tableRetry.delete(new Delete(Bytes.toBytes("row")).addColumn(CF, CQ));
128  }
129
130  @Test(expected = RetriesExhaustedException.class)
131  public void testAppendWithIOException() throws Exception {
132    tableRetry.append(new Append(Bytes.toBytes("row")).addColumn(CF, CQ, Bytes.toBytes("value")));
133  }
134
135  @Test(expected = RetriesExhaustedException.class)
136  public void testIncrementWithIOException() throws Exception {
137    tableRetry.increment(new Increment(Bytes.toBytes("row")).addColumn(CF, CQ, 1));
138  }
139
140  public static class ThrowDoNotRetryIOExceptionCoprocessor
141    implements RegionCoprocessor, RegionObserver {
142
143    public ThrowDoNotRetryIOExceptionCoprocessor() {
144    }
145
146    @Override
147    public Optional<RegionObserver> getRegionObserver() {
148      return Optional.of(this);
149    }
150
151    @Override
152    public void preGetOp(final ObserverContext<RegionCoprocessorEnvironment> e, final Get get,
153      final List<Cell> results) throws IOException {
154      throw new DoNotRetryIOException("Call failed and don't retry");
155    }
156
157    @Override
158    public void prePut(final ObserverContext<RegionCoprocessorEnvironment> e, final Put put,
159      final WALEdit edit, final Durability durability) throws IOException {
160      throw new DoNotRetryIOException("Call failed and don't retry");
161    }
162
163    @Override
164    public void preDelete(final ObserverContext<RegionCoprocessorEnvironment> e,
165      final Delete delete, final WALEdit edit, final Durability durability) throws IOException {
166      throw new DoNotRetryIOException("Call failed and don't retry");
167    }
168
169    @Override
170    public Result preIncrement(final ObserverContext<RegionCoprocessorEnvironment> e,
171      final Increment increment) throws IOException {
172      throw new DoNotRetryIOException("Call failed and don't retry");
173    }
174
175    @Override
176    public Result preAppend(final ObserverContext<RegionCoprocessorEnvironment> e,
177      final Append append) throws IOException {
178      throw new DoNotRetryIOException("Call failed and don't retry");
179    }
180  }
181
182  public static class ThrowIOExceptionCoprocessor implements RegionCoprocessor, RegionObserver {
183
184    public ThrowIOExceptionCoprocessor() {
185    }
186
187    @Override
188    public Optional<RegionObserver> getRegionObserver() {
189      return Optional.of(this);
190    }
191
192    @Override
193    public void preGetOp(final ObserverContext<RegionCoprocessorEnvironment> e, final Get get,
194      final List<Cell> results) throws IOException {
195      throw new IOException("Call failed and retry");
196    }
197
198    @Override
199    public void prePut(final ObserverContext<RegionCoprocessorEnvironment> e, final Put put,
200      final WALEdit edit, final Durability durability) throws IOException {
201      throw new IOException("Call failed and retry");
202    }
203
204    @Override
205    public void preDelete(final ObserverContext<RegionCoprocessorEnvironment> e,
206      final Delete delete, final WALEdit edit, final Durability durability) throws IOException {
207      throw new IOException("Call failed and retry");
208    }
209
210    @Override
211    public Result preIncrement(final ObserverContext<RegionCoprocessorEnvironment> e,
212      final Increment increment) throws IOException {
213      throw new IOException("Call failed and retry");
214    }
215
216    @Override
217    public Result preAppend(final ObserverContext<RegionCoprocessorEnvironment> e,
218      final Append append) throws IOException {
219      throw new IOException("Call failed and retry");
220    }
221  }
222}