1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.master.cleaner;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertTrue;
23
24 import java.io.IOException;
25
26 import org.apache.hadoop.conf.Configuration;
27 import org.apache.hadoop.fs.FileStatus;
28 import org.apache.hadoop.fs.FileSystem;
29 import org.apache.hadoop.fs.Path;
30 import org.apache.hadoop.hbase.ChoreService;
31 import org.apache.hadoop.hbase.CoordinatedStateManager;
32 import org.apache.hadoop.hbase.HBaseTestingUtility;
33 import org.apache.hadoop.hbase.HRegionInfo;
34 import org.apache.hadoop.hbase.Server;
35 import org.apache.hadoop.hbase.ServerName;
36 import org.apache.hadoop.hbase.TableName;
37 import org.apache.hadoop.hbase.client.ClusterConnection;
38 import org.apache.hadoop.hbase.io.HFileLink;
39 import org.apache.hadoop.hbase.testclassification.MediumTests;
40 import org.apache.hadoop.hbase.util.FSUtils;
41 import org.apache.hadoop.hbase.util.HFileArchiveUtil;
42 import org.apache.hadoop.hbase.zookeeper.MetaTableLocator;
43 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
44 import org.junit.AfterClass;
45 import org.junit.BeforeClass;
46 import org.junit.Test;
47 import org.junit.experimental.categories.Category;
48
49
50
51
52 @Category(MediumTests.class)
53 public class TestHFileLinkCleaner {
54
55 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
56
57 private static DirScanPool POOL;
58
59 @BeforeClass
60 public static void setUp() {
61 POOL = new DirScanPool(TEST_UTIL.getConfiguration());
62 }
63
64 @AfterClass
65 public static void tearDown() {
66 POOL.shutdownNow();
67 }
68
69 @Test
70 public void testHFileLinkCleaning() throws Exception {
71 Configuration conf = TEST_UTIL.getConfiguration();
72 FSUtils.setRootDir(conf, TEST_UTIL.getDataTestDir());
73 conf.set(HFileCleaner.MASTER_HFILE_CLEANER_PLUGINS, HFileLinkCleaner.class.getName());
74 Path rootDir = FSUtils.getRootDir(conf);
75 FileSystem fs = FileSystem.get(conf);
76
77 final TableName tableName = TableName.valueOf("test-table");
78 final TableName tableLinkName = TableName.valueOf("test-link");
79 final String hfileName = "1234567890";
80 final String familyName = "cf";
81
82 HRegionInfo hri = new HRegionInfo(tableName);
83 HRegionInfo hriLink = new HRegionInfo(tableLinkName);
84
85 Path archiveDir = HFileArchiveUtil.getArchivePath(conf);
86 Path archiveStoreDir = HFileArchiveUtil.getStoreArchivePath(conf,
87 tableName, hri.getEncodedName(), familyName);
88 Path archiveLinkStoreDir = HFileArchiveUtil.getStoreArchivePath(conf,
89 tableLinkName, hriLink.getEncodedName(), familyName);
90
91
92 Path familyPath = getFamilyDirPath(archiveDir, tableName, hri.getEncodedName(), familyName);
93 fs.mkdirs(familyPath);
94 Path hfilePath = new Path(familyPath, hfileName);
95 fs.createNewFile(hfilePath);
96
97
98 Path familyLinkPath = getFamilyDirPath(rootDir, tableLinkName,
99 hriLink.getEncodedName(), familyName);
100 fs.mkdirs(familyLinkPath);
101 HFileLink.create(conf, fs, familyLinkPath, hri, hfileName);
102 Path linkBackRefDir = HFileLink.getBackReferencesDir(archiveStoreDir, hfileName);
103 assertTrue(fs.exists(linkBackRefDir));
104 FileStatus[] backRefs = fs.listStatus(linkBackRefDir);
105 assertEquals(1, backRefs.length);
106 Path linkBackRef = backRefs[0].getPath();
107
108
109 final long ttl = 1000;
110 conf.setLong(TimeToLiveHFileCleaner.TTL_CONF_KEY, ttl);
111 Server server = new DummyServer();
112 HFileCleaner cleaner = new HFileCleaner(1000, server, conf, fs, archiveDir, POOL);
113
114
115 cleaner.chore();
116 assertTrue(fs.exists(linkBackRef));
117 assertTrue(fs.exists(hfilePath));
118
119
120 fs.rename(FSUtils.getTableDir(rootDir, tableLinkName),
121 FSUtils.getTableDir(archiveDir, tableLinkName));
122 cleaner.chore();
123 assertFalse("Link should be deleted", fs.exists(linkBackRef));
124
125
126 Thread.sleep(ttl * 2);
127 cleaner.chore();
128 assertFalse("HFile should be deleted", fs.exists(hfilePath));
129
130
131 for (int i = 0; i < 4; ++i) {
132 Thread.sleep(ttl * 2);
133 cleaner.chore();
134 }
135 assertFalse("HFile should be deleted", fs.exists(FSUtils.getTableDir(archiveDir, tableName)));
136 assertFalse("Link should be deleted", fs.exists(FSUtils.getTableDir(archiveDir, tableLinkName)));
137 }
138
139 private static Path getFamilyDirPath (final Path rootDir, final TableName table,
140 final String region, final String family) {
141 return new Path(new Path(FSUtils.getTableDir(rootDir, table), region), family);
142 }
143
144 static class DummyServer implements Server {
145
146 @Override
147 public Configuration getConfiguration() {
148 return TEST_UTIL.getConfiguration();
149 }
150
151 @Override
152 public ZooKeeperWatcher getZooKeeper() {
153 try {
154 return new ZooKeeperWatcher(getConfiguration(), "dummy server", this);
155 } catch (IOException e) {
156 e.printStackTrace();
157 }
158 return null;
159 }
160
161 @Override
162 public CoordinatedStateManager getCoordinatedStateManager() {
163 return null;
164 }
165
166 @Override
167 public ClusterConnection getConnection() {
168 return null;
169 }
170
171 @Override
172 public MetaTableLocator getMetaTableLocator() {
173 return null;
174 }
175
176 @Override
177 public ServerName getServerName() {
178 return ServerName.valueOf("regionserver,60020,000000");
179 }
180
181 @Override
182 public void abort(String why, Throwable e) {}
183
184 @Override
185 public boolean isAborted() {
186 return false;
187 }
188
189 @Override
190 public void stop(String why) {}
191
192 @Override
193 public boolean isStopped() {
194 return false;
195 }
196
197 @Override
198 public ChoreService getChoreService() {
199 return null;
200 }
201 }
202 }