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.master.cleaner; 019 020import static org.junit.Assert.assertFalse; 021import static org.junit.Assert.assertTrue; 022import static org.junit.Assert.fail; 023 024import java.io.IOException; 025import java.io.UncheckedIOException; 026import java.util.ArrayList; 027import java.util.Iterator; 028import java.util.List; 029import java.util.Map; 030import org.apache.hadoop.conf.Configuration; 031import org.apache.hadoop.fs.FileStatus; 032import org.apache.hadoop.fs.FileSystem; 033import org.apache.hadoop.fs.Path; 034import org.apache.hadoop.hbase.HBaseClassTestRule; 035import org.apache.hadoop.hbase.HBaseTestingUtil; 036import org.apache.hadoop.hbase.HConstants; 037import org.apache.hadoop.hbase.Server; 038import org.apache.hadoop.hbase.TableName; 039import org.apache.hadoop.hbase.client.Connection; 040import org.apache.hadoop.hbase.client.TableDescriptor; 041import org.apache.hadoop.hbase.master.HMaster; 042import org.apache.hadoop.hbase.replication.ReplicationException; 043import org.apache.hadoop.hbase.replication.ReplicationFactory; 044import org.apache.hadoop.hbase.replication.ReplicationPeerConfig; 045import org.apache.hadoop.hbase.replication.ReplicationPeers; 046import org.apache.hadoop.hbase.replication.ReplicationQueueStorage; 047import org.apache.hadoop.hbase.replication.ReplicationStorageFactory; 048import org.apache.hadoop.hbase.replication.SyncReplicationState; 049import org.apache.hadoop.hbase.replication.master.ReplicationHFileCleaner; 050import org.apache.hadoop.hbase.testclassification.MasterTests; 051import org.apache.hadoop.hbase.testclassification.SmallTests; 052import org.apache.hadoop.hbase.util.MockServer; 053import org.apache.hadoop.hbase.util.Pair; 054import org.apache.hadoop.hbase.zookeeper.ZKWatcher; 055import org.junit.After; 056import org.junit.AfterClass; 057import org.junit.Before; 058import org.junit.BeforeClass; 059import org.junit.ClassRule; 060import org.junit.Test; 061import org.junit.experimental.categories.Category; 062import org.slf4j.Logger; 063import org.slf4j.LoggerFactory; 064 065import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap; 066 067@Category({ MasterTests.class, SmallTests.class }) 068public class TestReplicationHFileCleaner { 069 070 @ClassRule 071 public static final HBaseClassTestRule CLASS_RULE = 072 HBaseClassTestRule.forClass(TestReplicationHFileCleaner.class); 073 074 private static final Logger LOG = LoggerFactory.getLogger(TestReplicationHFileCleaner.class); 075 private final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 076 private static Server server; 077 private static final TableName tableName = TableName.valueOf("test_cleaner"); 078 private static ReplicationQueueStorage rq; 079 private static ReplicationPeers rp; 080 private static final String peerId = "TestReplicationHFileCleaner"; 081 private static Configuration conf = TEST_UTIL.getConfiguration(); 082 private static FileSystem fs = null; 083 private static Map<String, Object> params; 084 private Path root; 085 086 @BeforeClass 087 public static void setUpBeforeClass() throws Exception { 088 TEST_UTIL.startMiniCluster(); 089 server = new DummyServer(); 090 params = ImmutableMap.of(HMaster.MASTER, server); 091 conf.setBoolean(HConstants.REPLICATION_BULKLOAD_ENABLE_KEY, true); 092 HMaster.decorateMasterConfiguration(conf); 093 TableDescriptor td = ReplicationStorageFactory.createReplicationQueueTableDescriptor(tableName); 094 TEST_UTIL.getAdmin().createTable(td); 095 conf.set(ReplicationStorageFactory.REPLICATION_QUEUE_TABLE_NAME, tableName.getNameAsString()); 096 rp = 097 ReplicationFactory.getReplicationPeers(server.getFileSystem(), server.getZooKeeper(), conf); 098 rp.init(); 099 rq = ReplicationStorageFactory.getReplicationQueueStorage(server.getConnection(), conf); 100 fs = FileSystem.get(conf); 101 } 102 103 @AfterClass 104 public static void tearDownAfterClass() throws Exception { 105 TEST_UTIL.shutdownMiniCluster(); 106 } 107 108 @Before 109 public void setup() throws ReplicationException, IOException { 110 root = TEST_UTIL.getDataTestDirOnTestFS(); 111 rp.getPeerStorage().addPeer(peerId, 112 ReplicationPeerConfig.newBuilder().setClusterKey(TEST_UTIL.getRpcConnnectionURI()).build(), 113 true, SyncReplicationState.NONE); 114 } 115 116 @After 117 public void cleanup() throws ReplicationException { 118 try { 119 fs.delete(root, true); 120 } catch (IOException e) { 121 LOG.warn("Failed to delete files recursively from path " + root); 122 } 123 // Remove all HFileRefs (if any) 124 rq.removeHFileRefs(peerId, rq.getReplicableHFiles(peerId)); 125 rp.getPeerStorage().removePeer(peerId); 126 } 127 128 private ReplicationHFileCleaner createCleaner() { 129 ReplicationHFileCleaner cleaner = new ReplicationHFileCleaner(); 130 cleaner.setConf(conf); 131 cleaner.init(params); 132 return cleaner; 133 } 134 135 @Test 136 public void testIsFileDeletable() throws IOException, ReplicationException { 137 // 1. Create a file 138 Path file = new Path(root, "testIsFileDeletableWithNoHFileRefs"); 139 fs.createNewFile(file); 140 // 2. Assert file is successfully created 141 assertTrue("Test file not created!", fs.exists(file)); 142 ReplicationHFileCleaner cleaner = createCleaner(); 143 // 3. Assert that file as is should be deletable 144 assertTrue("Cleaner should allow to delete this file as there is no hfile reference node " 145 + "for it in the queue.", cleaner.isFileDeletable(fs.getFileStatus(file))); 146 147 List<Pair<Path, Path>> files = new ArrayList<>(1); 148 files.add(new Pair<>(null, file)); 149 // 4. Add the file to hfile-refs queue 150 rq.addHFileRefs(peerId, files); 151 // 5. Assert file should not be deletable 152 assertFalse("Cleaner should not allow to delete this file as there is a hfile reference node " 153 + "for it in the queue.", cleaner.isFileDeletable(fs.getFileStatus(file))); 154 } 155 156 @Test 157 public void testGetDeletableFiles() throws Exception { 158 // 1. Create two files and assert that they do not exist 159 Path notDeletablefile = new Path(root, "testGetDeletableFiles_1"); 160 fs.createNewFile(notDeletablefile); 161 assertTrue("Test file not created!", fs.exists(notDeletablefile)); 162 Path deletablefile = new Path(root, "testGetDeletableFiles_2"); 163 fs.createNewFile(deletablefile); 164 assertTrue("Test file not created!", fs.exists(deletablefile)); 165 166 List<FileStatus> files = new ArrayList<>(2); 167 FileStatus f = new FileStatus(); 168 f.setPath(deletablefile); 169 files.add(f); 170 f = new FileStatus(); 171 f.setPath(notDeletablefile); 172 files.add(f); 173 174 List<Pair<Path, Path>> hfiles = new ArrayList<>(1); 175 hfiles.add(new Pair<>(null, notDeletablefile)); 176 // 2. Add one file to hfile-refs queue 177 rq.addHFileRefs(peerId, hfiles); 178 179 ReplicationHFileCleaner cleaner = createCleaner(); 180 Iterator<FileStatus> deletableFilesIterator = cleaner.getDeletableFiles(files).iterator(); 181 int i = 0; 182 while (deletableFilesIterator.hasNext() && i < 2) { 183 i++; 184 } 185 // 5. Assert one file should not be deletable and it is present in the list returned 186 if (i > 2) { 187 fail("File " + notDeletablefile 188 + " should not be deletable as its hfile reference node is not added."); 189 } 190 assertTrue(deletableFilesIterator.next().getPath().equals(deletablefile)); 191 } 192 193 static class DummyServer extends MockServer { 194 195 @Override 196 public Configuration getConfiguration() { 197 return TEST_UTIL.getConfiguration(); 198 } 199 200 @Override 201 public ZKWatcher getZooKeeper() { 202 try { 203 return TEST_UTIL.getZooKeeperWatcher(); 204 } catch (IOException e) { 205 throw new UncheckedIOException(e); 206 } 207 } 208 209 @Override 210 public Connection getConnection() { 211 try { 212 return TEST_UTIL.getConnection(); 213 } catch (IOException e) { 214 throw new UncheckedIOException(e); 215 } 216 } 217 218 @Override 219 public FileSystem getFileSystem() { 220 try { 221 return TEST_UTIL.getTestFileSystem(); 222 } catch (IOException e) { 223 throw new UncheckedIOException(e); 224 } 225 } 226 } 227}