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;
19  
20  import static org.junit.Assert.assertTrue;
21  
22  import java.io.IOException;
23  import java.net.URI;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.fs.FSDataInputStream;
29  import org.apache.hadoop.fs.FSDataOutputStream;
30  import org.apache.hadoop.fs.FileStatus;
31  import org.apache.hadoop.fs.FileSystem;
32  import org.apache.hadoop.fs.Path;
33  import org.apache.hadoop.fs.permission.FsPermission;
34  import org.apache.hadoop.util.Progressable;
35  import org.junit.BeforeClass;
36  import org.junit.Test;
37  import org.junit.experimental.categories.Category;
38  
39  @Category(MediumTests.class)
40  public class TestHBaseFileSystem {
41    public static final Log LOG = LogFactory.getLog(TestHBaseFileSystem.class);
42  
43    private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
44    private static Configuration conf;
45  
46    @BeforeClass
47    public static void setUpBeforeClass() throws Exception {
48      conf = TEST_UTIL.getConfiguration();
49      conf.setBoolean("dfs.support.append", true);
50      // The below config supported by 0.20-append and CDH3b2
51      conf.setInt("dfs.client.block.recovery.retries", 2);
52      TEST_UTIL.startMiniDFSCluster(3);
53      Path hbaseRootDir =
54        TEST_UTIL.getDFSCluster().getFileSystem().makeQualified(new Path("/hbase"));
55      LOG.info("hbase.rootdir=" + hbaseRootDir);
56      conf.set(HConstants.HBASE_DIR, hbaseRootDir.toString());
57      conf.setInt("hdfs.client.retries.number", 10);
58      HBaseFileSystem.setRetryCounts(conf);
59    }
60  
61    
62    @Test
63    public void testNonIdempotentOpsWithRetries() throws IOException {
64      LOG.info("testNonIdempotentOpsWithRetries");
65  
66      Path rootDir = new Path(TestHBaseFileSystem.conf.get(HConstants.HBASE_DIR));
67      FileSystem fs = TEST_UTIL.getTestFileSystem();
68      // Create a Region
69      assertTrue(HBaseFileSystem.createPathOnFileSystem(fs, rootDir, 
70        true) != null);
71  
72      boolean result = HBaseFileSystem.makeDirOnFileSystem(new MockFileSystemForCreate(), 
73        new Path("/a"));
74      assertTrue("Couldn't create the directory", result);
75  
76      try {
77        HBaseFileSystem.createPathOnFileSystem(new MockFileSystemForCreate(), 
78          new Path("/A"), false);
79       assertTrue(false);// control should not come here.
80      } catch (Exception e) {
81        LOG.info(e);
82      }
83  
84      result = HBaseFileSystem.renameDirForFileSystem(new MockFileSystem(), new Path("/a"),
85        new Path("/b"));
86      assertTrue("Couldn't rename the directory", result);
87  
88      result = HBaseFileSystem.deleteDirFromFileSystem(new MockFileSystem(), 
89        new Path("/a"));
90  
91      assertTrue("Couldn't delete the directory", result);
92      fs.delete(rootDir, true);
93    }
94  
95    static class MockFileSystemForCreate extends MockFileSystem {
96      @Override
97      public boolean exists(Path path) {
98        if ("/A".equals(path.toString())) return true;
99        return false;
100     }
101   }
102 
103   /**
104    * a mock fs which throws exception for first 3 times, and then process the call (returns the
105    * excepted result).
106    */
107   static class MockFileSystem extends FileSystem {
108     int retryCount;
109     final static int successRetryCount = 3;
110 
111     public MockFileSystem() {
112       retryCount = 0;
113     }
114 
115     @Override
116     public FSDataOutputStream append(Path arg0, int arg1, Progressable arg2) throws IOException {
117       throw new IOException("");
118     }
119 
120     @Override
121     public FSDataOutputStream create(Path arg0, FsPermission arg1, boolean arg2, int arg3,
122         short arg4, long arg5, Progressable arg6) throws IOException {
123       LOG.debug("Create, " + retryCount);
124       if (retryCount++ < successRetryCount) throw new IOException("Something bad happen");
125       return null;
126     }
127 
128     @Override
129     public boolean delete(Path arg0) throws IOException {
130       if (retryCount++ < successRetryCount) throw new IOException("Something bad happen");
131       return true;
132     }
133 
134     @Override
135     public boolean delete(Path arg0, boolean arg1) throws IOException {
136       if (retryCount++ < successRetryCount) throw new IOException("Something bad happen");
137       return true;
138     }
139 
140     @Override
141     public FileStatus getFileStatus(Path arg0) throws IOException {
142       FileStatus fs = new FileStatus();
143       return fs;
144     }
145 
146     @Override
147     public boolean exists(Path path) {
148       return true;
149     }
150 
151     @Override
152     public URI getUri() {
153       throw new RuntimeException("Something bad happen");
154     }
155 
156     @Override
157     public Path getWorkingDirectory() {
158       throw new RuntimeException("Something bad happen");
159     }
160 
161     @Override
162     public FileStatus[] listStatus(Path arg0) throws IOException {
163       throw new IOException("Something bad happen");
164     }
165 
166     @Override
167     public boolean mkdirs(Path arg0, FsPermission arg1) throws IOException {
168       LOG.debug("mkdirs, " + retryCount);
169       if (retryCount++ < successRetryCount) throw new IOException("Something bad happen");
170       return true;
171     }
172 
173     @Override
174     public FSDataInputStream open(Path arg0, int arg1) throws IOException {
175       throw new IOException("Something bad happen");
176     }
177 
178     @Override
179     public boolean rename(Path arg0, Path arg1) throws IOException {
180       LOG.debug("rename, " + retryCount);
181       if (retryCount++ < successRetryCount) throw new IOException("Something bad happen");
182       return true;
183     }
184 
185     @Override
186     public void setWorkingDirectory(Path arg0) {
187       throw new RuntimeException("Something bad happen");
188     }
189   }
190 
191 }