1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.master.snapshot;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertTrue;
23 import static org.mockito.Mockito.mock;
24 import static org.mockito.Mockito.when;
25
26 import java.io.IOException;
27 import java.util.*;
28 import java.util.concurrent.atomic.AtomicInteger;
29
30 import com.google.common.collect.Iterables;
31 import com.google.common.collect.Lists;
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.hadoop.fs.FileStatus;
35 import org.apache.hadoop.fs.FileSystem;
36 import org.apache.hadoop.fs.Path;
37 import org.apache.hadoop.hbase.HBaseTestingUtility;
38 import org.apache.hadoop.hbase.HRegionInfo;
39 import org.apache.hadoop.hbase.protobuf.generated.SnapshotProtos;
40 import org.apache.hadoop.hbase.testclassification.MediumTests;
41 import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
42 import org.apache.hadoop.hbase.snapshot.SnapshotReferenceUtil;
43 import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils.SnapshotMock;
44 import org.apache.hadoop.hbase.util.FSUtils;
45 import org.junit.After;
46 import org.junit.AfterClass;
47 import org.junit.BeforeClass;
48 import org.junit.Ignore;
49 import org.junit.Test;
50 import org.junit.experimental.categories.Category;
51
52
53
54
55 @Category(MediumTests.class)
56 public class TestSnapshotFileCache {
57
58 private static final Log LOG = LogFactory.getLog(TestSnapshotFileCache.class);
59 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
60 private static long sequenceId = 0;
61 private static FileSystem fs;
62 private static Path rootDir;
63
64 @BeforeClass
65 public static void startCluster() throws Exception {
66 UTIL.startMiniDFSCluster(1);
67 fs = UTIL.getDFSCluster().getFileSystem();
68 rootDir = UTIL.getDefaultRootDirPath();
69 }
70
71 @AfterClass
72 public static void stopCluster() throws Exception {
73 UTIL.shutdownMiniDFSCluster();
74 }
75
76 @After
77 public void cleanupFiles() throws Exception {
78
79 Path snapshotDir = SnapshotDescriptionUtils.getSnapshotsDir(rootDir);
80 fs.delete(snapshotDir, true);
81 }
82
83 @Test(timeout = 10000000)
84 @Ignore("See HBASE-19275")
85 public void testLoadAndDelete() throws IOException {
86
87 long period = Long.MAX_VALUE;
88 SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, period, 10000000,
89 "test-snapshot-file-cache-refresh", new SnapshotFiles());
90
91 createAndTestSnapshotV1(cache, "snapshot1a", false, true);
92 createAndTestSnapshotV1(cache, "snapshot1b", true, true);
93
94 createAndTestSnapshotV2(cache, "snapshot2a", false, true);
95 createAndTestSnapshotV2(cache, "snapshot2b", true, true);
96 }
97
98 @Test
99 @Ignore("See HBASE-19275")
100 public void testReloadModifiedDirectory() throws IOException {
101
102 long period = Long.MAX_VALUE;
103 SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, period, 10000000,
104 "test-snapshot-file-cache-refresh", new SnapshotFiles());
105
106 createAndTestSnapshotV1(cache, "snapshot1", false, true);
107
108 createAndTestSnapshotV1(cache, "snapshot1", false, false);
109
110 createAndTestSnapshotV2(cache, "snapshot2", false, true);
111
112 createAndTestSnapshotV2(cache, "snapshot2", false, false);
113 }
114
115 @Test
116 public void testSnapshotTempDirReload() throws IOException {
117 long period = Long.MAX_VALUE;
118
119 SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, period, 10000000,
120 "test-snapshot-file-cache-refresh", new SnapshotFiles());
121
122
123 createAndTestSnapshotV1(cache, "snapshot0v1", false, false);
124 createAndTestSnapshotV1(cache, "snapshot0v2", false, false);
125
126
127 createAndTestSnapshotV2(cache, "snapshot1", true, false);
128
129
130 createAndTestSnapshotV2(cache, "snapshot2", true, false);
131 }
132
133 @Test
134 public void testWeNeverCacheTmpDirAndLoadIt() throws Exception {
135
136 final AtomicInteger count = new AtomicInteger(0);
137
138 long period = Long.MAX_VALUE;
139 SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, period, 10000000,
140 "test-snapshot-file-cache-refresh", new SnapshotFiles()) {
141 @Override
142 List<String> getSnapshotsInProgress(final SnapshotManager snapshotManager)
143 throws IOException {
144 List<String> result = super.getSnapshotsInProgress(snapshotManager);
145 count.incrementAndGet();
146 return result;
147 }
148
149 @Override public void triggerCacheRefreshForTesting() {
150 super.triggerCacheRefreshForTesting();
151 }
152 };
153
154 SnapshotMock.SnapshotBuilder complete =
155 createAndTestSnapshotV1(cache, "snapshot", false, false);
156
157 SnapshotMock.SnapshotBuilder inProgress =
158 createAndTestSnapshotV1(cache, "snapshotInProgress", true, false);
159
160 int countBeforeCheck = count.get();
161
162 FSUtils.logFileSystemState(fs, rootDir, LOG);
163
164 List<FileStatus> allStoreFiles = getStoreFilesForSnapshot(complete);
165 Iterable<FileStatus> deletableFiles = cache.getUnreferencedFiles(allStoreFiles, null);
166 assertTrue(Iterables.isEmpty(deletableFiles));
167
168 assertEquals(0, count.get() - countBeforeCheck);
169
170
171
172 FileStatus randomFile = mockStoreFile(UUID.randomUUID().toString());
173 allStoreFiles.add(randomFile);
174 deletableFiles = cache.getUnreferencedFiles(allStoreFiles, null);
175 assertEquals(randomFile, Iterables.getOnlyElement(deletableFiles));
176 assertEquals(1, count.get() - countBeforeCheck);
177 }
178
179 private List<FileStatus> getStoreFilesForSnapshot(SnapshotMock.SnapshotBuilder builder)
180 throws IOException {
181 final List<FileStatus> allStoreFiles = Lists.newArrayList();
182 SnapshotReferenceUtil
183 .visitReferencedFiles(UTIL.getConfiguration(), fs, builder.getSnapshotsDir(),
184 new SnapshotReferenceUtil.SnapshotVisitor() {
185 @Override public void storeFile(HRegionInfo regionInfo, String familyName,
186 SnapshotProtos.SnapshotRegionManifest.StoreFile storeFile) throws IOException {
187 FileStatus status = mockStoreFile(storeFile.getName());
188 allStoreFiles.add(status);
189 }
190 });
191 return allStoreFiles;
192 }
193
194 private FileStatus mockStoreFile(String storeFileName) {
195 FileStatus status = mock(FileStatus.class);
196 Path path = mock(Path.class);
197 when(path.getName()).thenReturn(storeFileName);
198 when(status.getPath()).thenReturn(path);
199 return status;
200 }
201
202 class SnapshotFiles implements SnapshotFileCache.SnapshotFileInspector {
203 public Collection<String> filesUnderSnapshot(final Path snapshotDir) throws IOException {
204 Collection<String> files = new HashSet<String>();
205 files.addAll(SnapshotReferenceUtil.getHFileNames(UTIL.getConfiguration(), fs, snapshotDir));
206 return files;
207 }
208 };
209
210 private SnapshotMock.SnapshotBuilder createAndTestSnapshotV1(final SnapshotFileCache cache,
211 final String name, final boolean tmp, final boolean removeOnExit) throws IOException {
212 SnapshotMock snapshotMock = new SnapshotMock(UTIL.getConfiguration(), fs, rootDir);
213 SnapshotMock.SnapshotBuilder builder = snapshotMock.createSnapshotV1(name, name);
214 createAndTestSnapshot(cache, builder, tmp, removeOnExit);
215 return builder;
216 }
217
218 private void createAndTestSnapshotV2(final SnapshotFileCache cache, final String name,
219 final boolean tmp, final boolean removeOnExit) throws IOException {
220 SnapshotMock snapshotMock = new SnapshotMock(UTIL.getConfiguration(), fs, rootDir);
221 SnapshotMock.SnapshotBuilder builder = snapshotMock.createSnapshotV2(name, name);
222 createAndTestSnapshot(cache, builder, tmp, removeOnExit);
223 }
224
225 private void createAndTestSnapshot(final SnapshotFileCache cache,
226 final SnapshotMock.SnapshotBuilder builder,
227 final boolean tmp, final boolean removeOnExit) throws IOException {
228 List<Path> files = new ArrayList<Path>();
229 for (int i = 0; i < 3; ++i) {
230 for (Path filePath: builder.addRegion()) {
231 String fileName = filePath.getName();
232 if (tmp) {
233
234 FSUtils.logFileSystemState(fs, rootDir, LOG);
235 Iterable<FileStatus> nonSnapshot = getNonSnapshotFiles(cache, filePath);
236 assertFalse("Cache didn't find " + fileName, Iterables.contains(nonSnapshot, fileName));
237 }
238 files.add(filePath);
239 }
240 }
241
242
243 if (!tmp) {
244 builder.commit();
245 }
246
247
248 for (Path path: files) {
249 Iterable<FileStatus> nonSnapshotFiles = getNonSnapshotFiles(cache, path);
250 assertFalse("Cache didn't find " + path.getName(),
251 Iterables.contains(nonSnapshotFiles, path.getName()));
252 }
253
254 FSUtils.logFileSystemState(fs, rootDir, LOG);
255 if (removeOnExit) {
256 LOG.debug("Deleting snapshot.");
257 fs.delete(builder.getSnapshotsDir(), true);
258 FSUtils.logFileSystemState(fs, rootDir, LOG);
259
260
261 for (Path filePath: files) {
262 Iterable<FileStatus> nonSnapshotFiles = getNonSnapshotFiles(cache, filePath);
263 assertFalse("Cache didn't find " + filePath.getName(), Iterables.contains(nonSnapshotFiles,
264 filePath.getName()));
265 }
266
267
268 cache.triggerCacheRefreshForTesting();
269
270
271 for (Path filePath: files) {
272 Iterable<FileStatus> nonSnapshotFiles = getNonSnapshotFiles(cache, filePath);
273 assertTrue("Cache found '" + filePath.getName() + "', but it shouldn't have.",
274 !Iterables.contains(nonSnapshotFiles, filePath.getName()));
275 }
276 }
277 }
278
279 private Iterable<FileStatus> getNonSnapshotFiles(SnapshotFileCache cache, Path storeFile)
280 throws IOException {
281 return cache.getUnreferencedFiles(
282 Arrays.asList(FSUtils.listStatus(fs, storeFile.getParent())), null
283 );
284 }
285 }