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