View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.regionserver.wal;
19  
20  import java.io.IOException;
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.hadoop.conf.Configuration;
24  import org.apache.hadoop.fs.FileSystem;
25  import org.apache.hadoop.fs.Path;
26  import org.apache.hadoop.hbase.HBaseTestingUtility;
27  import org.apache.hadoop.hbase.HConstants;
28  import org.apache.hadoop.hbase.TableName;
29  import org.apache.hadoop.hbase.client.Append;
30  import org.apache.hadoop.hbase.client.Durability;
31  import org.apache.hadoop.hbase.client.Increment;
32  import org.apache.hadoop.hbase.client.Put;
33  import org.apache.hadoop.hbase.exceptions.TimeoutIOException;
34  import org.apache.hadoop.hbase.regionserver.HRegion;
35  import org.apache.hadoop.hbase.regionserver.RegionServerServices;
36  import org.apache.hadoop.hbase.testclassification.MediumTests;
37  import org.apache.hadoop.hbase.testclassification.RegionServerTests;
38  import org.apache.hadoop.hbase.util.Bytes;
39  import org.apache.hadoop.hbase.wal.WAL;
40  import org.junit.After;
41  import org.junit.Before;
42  import org.junit.Rule;
43  import org.junit.Test;
44  import org.junit.experimental.categories.Category;
45  import org.junit.rules.TestName;
46  import org.mockito.Mockito;
47  
48  import static org.junit.Assert.assertTrue;
49  import static org.junit.Assert.fail;
50  import static org.mockito.Mockito.mock;
51  
52  /*
53    Testing RS abort in case if sync fails/times out.
54   */
55  @Category({MediumTests.class, RegionServerTests.class})
56  public class TestFSHLogTimedOutSync {
57    private static final Log LOG = LogFactory.getLog(TestFSHLogTimedOutSync.class);
58  
59    @Rule public TestName name = new TestName();
60  
61    private static final String COLUMN_FAMILY = "MyCF";
62    private static final byte [] COLUMN_FAMILY_BYTES = Bytes.toBytes(COLUMN_FAMILY);
63    private static final String COLUMN_QUALIFIER = "MyCQ";
64    private static final byte [] COLUMN_QUALIFIER_BYTES = Bytes.toBytes(COLUMN_QUALIFIER);
65    private static HBaseTestingUtility TEST_UTIL;
66    private static Configuration CONF ;
67    private String dir;
68  
69    // Test names
70    protected TableName tableName;
71  
72    @Before
73    public void setup() throws IOException {
74      TEST_UTIL = HBaseTestingUtility.createLocalHTU();
75      CONF = TEST_UTIL.getConfiguration();
76      // Disable block cache.
77      CONF.setFloat(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY, 0f);
78      dir = TEST_UTIL.getDataTestDir("TestHRegion").toString();
79      tableName = TableName.valueOf(name.getMethodName());
80    }
81  
82    @After
83    public void tearDown() throws Exception {
84      LOG.info("Cleaning test directory: " + TEST_UTIL.getDataTestDir());
85      TEST_UTIL.cleanupTestDir();
86    }
87  
88    // Test that RS aborts in case of put, append and increment when sync fails or times out.
89    @Test(timeout=30000)
90    public void testRSAbortWhenSyncTimedOut() throws IOException {
91      // Dodgy WAL. Will throw exceptions when flags set.
92      class DodgyFSLog extends FSHLog {
93        volatile boolean throwSyncException = false;
94  
95        public DodgyFSLog(FileSystem fs, Path root, String logDir, Configuration conf)
96          throws IOException {
97          super(fs, root, logDir, conf);
98        }
99  
100       @Override
101       public void sync(long txid) throws IOException {
102         super.sync(txid);
103         if (throwSyncException) {
104           throw new TimeoutIOException("Exception");
105         }
106       }
107 
108       @Override
109       public void sync(long txid, boolean force) throws IOException {
110         super.sync(txid, force);
111         if (throwSyncException) {
112           throw new TimeoutIOException("Exception");
113         }
114       }
115     }
116 
117     // Make up mocked server and services.
118     RegionServerServices services = mock(RegionServerServices.class);
119     FileSystem fs = FileSystem.get(CONF);
120     Path rootDir = new Path(dir + getName());
121     DodgyFSLog dodgyWAL = new DodgyFSLog(fs, rootDir, getName(), CONF);
122     HRegion region = initHRegion(tableName, null, null, CONF, dodgyWAL);
123     region.setRegionServerServices(services);
124     // Get some random bytes.
125     byte[] row = Bytes.toBytes(getName());
126     byte[] value = Bytes.toBytes(getName());
127     // Test Put operation
128     try {
129       dodgyWAL.throwSyncException = true;
130       Put put = new Put(row);
131       put.addColumn(COLUMN_FAMILY_BYTES, COLUMN_QUALIFIER_BYTES, value);
132       region.put(put);
133       fail();
134     } catch (IOException ioe) {
135       assertTrue(ioe instanceof TimeoutIOException);
136     }
137     // Verify that RS aborts
138     Mockito.verify(services, Mockito.times(1)).
139       abort(Mockito.anyString(), Mockito.<Throwable>anyObject());
140 
141     // Test Append operation
142     try {
143       dodgyWAL.throwSyncException = true;
144       Append a = new Append(row);
145       a.setReturnResults(false);
146       a.add(COLUMN_FAMILY_BYTES, COLUMN_QUALIFIER_BYTES, value);
147       region.append(a, HConstants.NO_NONCE, HConstants.NO_NONCE);
148       fail();
149     } catch (IOException ioe) {
150       assertTrue(ioe instanceof TimeoutIOException);
151     }
152     // Verify that RS aborts
153     Mockito.verify(services, Mockito.times(2)).
154       abort(Mockito.anyString(), Mockito.<Throwable>anyObject());
155 
156     // Test Increment operation
157     try {
158       dodgyWAL.throwSyncException = true;
159       final Increment inc = new Increment(row);
160       inc.addColumn(COLUMN_FAMILY_BYTES, Bytes.toBytes("qual2"), 1);
161       region.increment(inc, HConstants.NO_NONCE, HConstants.NO_NONCE);
162       fail();
163     } catch (IOException ioe) {
164       assertTrue(ioe instanceof TimeoutIOException);
165     }
166     // Verify that RS aborts
167     Mockito.verify(services, Mockito.times(3)).
168       abort(Mockito.anyString(), Mockito.<Throwable>anyObject());
169   }
170 
171   String getName() {
172     return name.getMethodName();
173   }
174 
175   /**
176    * @return A region on which you must call
177    *         {@link HBaseTestingUtility#closeRegionAndWAL(HRegion)} when done.
178    */
179   public HRegion initHRegion(TableName tableName, byte[] startKey, byte[] stopKey,
180     Configuration conf, WAL wal) throws IOException {
181     return TEST_UTIL.createLocalHRegion(tableName.getName(), startKey, stopKey,
182       getName(), conf, false, Durability.SYNC_WAL, wal, COLUMN_FAMILY_BYTES);
183   }
184 }