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.fs;
019
020import java.lang.reflect.Field;
021import org.apache.hadoop.conf.Configuration;
022import org.apache.hadoop.fs.FSDataOutputStream;
023import org.apache.hadoop.fs.FileSystem;
024import org.apache.hadoop.fs.Path;
025import org.apache.hadoop.hbase.HBaseClassTestRule;
026import org.apache.hadoop.hbase.HBaseTestingUtility;
027import org.apache.hadoop.hbase.HConstants;
028import org.apache.hadoop.hbase.MiniHBaseCluster;
029import org.apache.hadoop.hbase.testclassification.LargeTests;
030import org.apache.hadoop.hbase.testclassification.MiscTests;
031import org.apache.hadoop.hbase.wal.AbstractFSWALProvider;
032import org.apache.hadoop.hdfs.DFSClient;
033import org.apache.hadoop.hdfs.DistributedFileSystem;
034import org.apache.hadoop.hdfs.MiniDFSCluster;
035import org.apache.hadoop.hdfs.protocol.ClientProtocol;
036import org.apache.hadoop.hdfs.protocol.LocatedBlocks;
037import org.junit.After;
038import org.junit.Assert;
039import org.junit.Before;
040import org.junit.ClassRule;
041import org.junit.Rule;
042import org.junit.Test;
043import org.junit.experimental.categories.Category;
044import org.junit.rules.TestName;
045
046/**
047 * Tests for the hdfs fix from HBASE-6435.
048 *
049 * Please don't add new subtest which involves starting / stopping MiniDFSCluster in this class.
050 * When stopping MiniDFSCluster, shutdown hooks would be cleared in hadoop's ShutdownHookManager
051 *   in hadoop 3.
052 * This leads to 'Failed suppression of fs shutdown hook' error in region server.
053 */
054@Category({MiscTests.class, LargeTests.class})
055public class TestBlockReorderBlockLocation {
056
057  @ClassRule
058  public static final HBaseClassTestRule CLASS_RULE =
059      HBaseClassTestRule.forClass(TestBlockReorderBlockLocation.class);
060
061  private Configuration conf;
062  private MiniDFSCluster cluster;
063  private HBaseTestingUtility htu;
064  private DistributedFileSystem dfs;
065  private static final String host1 = "host1";
066  private static final String host2 = "host2";
067  private static final String host3 = "host3";
068
069  @Rule
070  public TestName name = new TestName();
071
072  @Before
073  public void setUp() throws Exception {
074    htu = new HBaseTestingUtility();
075    htu.getConfiguration().setInt("dfs.blocksize", 1024);// For the test with multiple blocks
076    htu.getConfiguration().setInt("dfs.replication", 3);
077    htu.startMiniDFSCluster(3,
078        new String[]{"/r1", "/r2", "/r3"}, new String[]{host1, host2, host3});
079
080    conf = htu.getConfiguration();
081    cluster = htu.getDFSCluster();
082    dfs = (DistributedFileSystem) FileSystem.get(conf);
083  }
084
085  @After
086  public void tearDownAfterClass() throws Exception {
087    htu.shutdownMiniCluster();
088  }
089
090
091  private static ClientProtocol getNamenode(DFSClient dfsc) throws Exception {
092    Field nf = DFSClient.class.getDeclaredField("namenode");
093    nf.setAccessible(true);
094    return (ClientProtocol) nf.get(dfsc);
095  }
096
097  /**
098   * Test that the reorder algo works as we expect.
099   */
100  @Test
101  public void testBlockLocation() throws Exception {
102    // We need to start HBase to get  HConstants.HBASE_DIR set in conf
103    htu.startMiniZKCluster();
104    MiniHBaseCluster hbm = htu.startMiniHBaseCluster();
105    conf = hbm.getConfiguration();
106
107
108    // The "/" is mandatory, without it we've got a null pointer exception on the namenode
109    final String fileName = "/helloWorld";
110    Path p = new Path(fileName);
111
112    final int repCount = 3;
113    Assert.assertTrue((short) cluster.getDataNodes().size() >= repCount);
114
115    // Let's write the file
116    FSDataOutputStream fop = dfs.create(p, (short) repCount);
117    final double toWrite = 875.5613;
118    fop.writeDouble(toWrite);
119    fop.close();
120
121    for (int i=0; i<10; i++){
122      // The interceptor is not set in this test, so we get the raw list at this point
123      LocatedBlocks l;
124      final long max = System.currentTimeMillis() + 10000;
125      do {
126        l = getNamenode(dfs.getClient()).getBlockLocations(fileName, 0, 1);
127        Assert.assertNotNull(l.getLocatedBlocks());
128        Assert.assertEquals(1, l.getLocatedBlocks().size());
129        Assert.assertTrue("Expecting " + repCount + " , got " + l.get(0).getLocations().length,
130            System.currentTimeMillis() < max);
131      } while (l.get(0).getLocations().length != repCount);
132
133      // Should be filtered, the name is different => The order won't change
134      Object originalList [] = l.getLocatedBlocks().toArray();
135      HFileSystem.ReorderWALBlocks lrb = new HFileSystem.ReorderWALBlocks();
136      lrb.reorderBlocks(conf, l, fileName);
137      Assert.assertArrayEquals(originalList, l.getLocatedBlocks().toArray());
138
139      // Should be reordered, as we pretend to be a file name with a compliant stuff
140      Assert.assertNotNull(conf.get(HConstants.HBASE_DIR));
141      Assert.assertFalse(conf.get(HConstants.HBASE_DIR).isEmpty());
142      String pseudoLogFile = conf.get(HConstants.HBASE_DIR) + "/" +
143          HConstants.HREGION_LOGDIR_NAME + "/" + host1 + ",6977,6576" + "/mylogfile";
144
145      // Check that it will be possible to extract a ServerName from our construction
146      Assert.assertNotNull("log= " + pseudoLogFile,
147        AbstractFSWALProvider.getServerNameFromWALDirectoryName(dfs.getConf(), pseudoLogFile));
148
149      // And check we're doing the right reorder.
150      lrb.reorderBlocks(conf, l, pseudoLogFile);
151      Assert.assertEquals(host1, l.get(0).getLocations()[2].getHostName());
152
153      // Check again, it should remain the same.
154      lrb.reorderBlocks(conf, l, pseudoLogFile);
155      Assert.assertEquals(host1, l.get(0).getLocations()[2].getHostName());
156    }
157  }
158
159}