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.protobuf.generated.HBaseProtos.SnapshotDescription;
42 import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
43 import org.apache.hadoop.hbase.snapshot.SnapshotReferenceUtil;
44 import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils.SnapshotMock;
45 import org.apache.hadoop.hbase.util.FSUtils;
46 import org.junit.After;
47 import org.junit.AfterClass;
48 import org.junit.BeforeClass;
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 public void testLoadAndDelete() throws IOException {
85
86 long period = Long.MAX_VALUE;
87 SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, period, 10000000,
88 "test-snapshot-file-cache-refresh", new SnapshotFiles());
89
90 createAndTestSnapshotV1(cache, "snapshot1a", false, true);
91 createAndTestSnapshotV1(cache, "snapshot1b", true, true);
92
93 createAndTestSnapshotV2(cache, "snapshot2a", false, true);
94 createAndTestSnapshotV2(cache, "snapshot2b", true, true);
95 }
96
97 @Test
98 public void testJustFindLogsDirectory() throws Exception {
99
100 long period = Long.MAX_VALUE;
101 Path snapshotDir = SnapshotDescriptionUtils.getSnapshotsDir(rootDir);
102 SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, period, 10000000,
103 "test-snapshot-file-cache-refresh", new SnapshotFileCache.SnapshotFileInspector() {
104 public Collection<String> filesUnderSnapshot(final Path snapshotDir)
105 throws IOException {
106 return SnapshotReferenceUtil.getWALNames(fs, snapshotDir);
107 }
108 });
109
110
111 SnapshotDescription desc = SnapshotDescription.newBuilder().setName("snapshot").build();
112 Path snapshot = SnapshotDescriptionUtils.getCompletedSnapshotDir(desc, rootDir);
113 SnapshotDescriptionUtils.writeSnapshotInfo(desc, snapshot, fs);
114 Path file1 = new Path(new Path(new Path(snapshot, "7e91021"), "fam"), "file1");
115 fs.createNewFile(file1);
116
117
118 Path logs = SnapshotReferenceUtil.getLogsDir(snapshot, "server");
119 Path log = new Path(logs, "me.hbase.com%2C58939%2C1350424310315.1350424315552");
120 fs.createNewFile(log);
121
122 FSUtils.logFileSystemState(fs, rootDir, LOG);
123
124
125 Iterable<FileStatus> notSnapshot = getNonSnapshotFiles(cache, file1);
126 assertFalse("Cache found '" + file1 + "', but it shouldn't have.",
127 Iterables.contains(notSnapshot, file1.getName()));
128 notSnapshot = getNonSnapshotFiles(cache, log);
129 assertTrue("Cache didn't find:" + log, !Iterables.contains(notSnapshot, log));
130 }
131
132 @Test
133 public void testReloadModifiedDirectory() throws IOException {
134
135 long period = Long.MAX_VALUE;
136 SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, period, 10000000,
137 "test-snapshot-file-cache-refresh", new SnapshotFiles());
138
139 createAndTestSnapshotV1(cache, "snapshot1", false, true);
140
141 createAndTestSnapshotV1(cache, "snapshot1", false, false);
142
143 createAndTestSnapshotV2(cache, "snapshot2", false, true);
144
145 createAndTestSnapshotV2(cache, "snapshot2", false, false);
146 }
147
148 @Test
149 public void testSnapshotTempDirReload() throws IOException {
150 long period = Long.MAX_VALUE;
151
152 SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, period, 10000000,
153 "test-snapshot-file-cache-refresh", new SnapshotFiles());
154
155
156 createAndTestSnapshotV1(cache, "snapshot0v1", false, false);
157 createAndTestSnapshotV1(cache, "snapshot0v2", false, false);
158
159
160 createAndTestSnapshotV2(cache, "snapshot1", true, false);
161
162
163 createAndTestSnapshotV2(cache, "snapshot2", true, false);
164 }
165
166 @Test
167 public void testWeNeverCacheTmpDirAndLoadIt() throws Exception {
168
169 final AtomicInteger count = new AtomicInteger(0);
170
171 long period = Long.MAX_VALUE;
172 SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, period, 10000000,
173 "test-snapshot-file-cache-refresh", new SnapshotFiles()) {
174 @Override
175 List<String> getSnapshotsInProgress() throws IOException {
176 List<String> result = super.getSnapshotsInProgress();
177 count.incrementAndGet();
178 return result;
179 }
180
181 @Override public void triggerCacheRefreshForTesting() {
182 super.triggerCacheRefreshForTesting();
183 }
184 };
185
186 SnapshotMock.SnapshotBuilder complete =
187 createAndTestSnapshotV1(cache, "snapshot", false, false);
188
189 SnapshotMock.SnapshotBuilder inProgress =
190 createAndTestSnapshotV1(cache, "snapshotInProgress", true, false);
191
192 int countBeforeCheck = count.get();
193
194 FSUtils.logFileSystemState(fs, rootDir, LOG);
195
196 List<FileStatus> allStoreFiles = getStoreFilesForSnapshot(complete);
197 Iterable<FileStatus> deletableFiles = cache.getUnreferencedFiles(allStoreFiles);
198 assertTrue(Iterables.isEmpty(deletableFiles));
199
200 assertEquals(0, count.get() - countBeforeCheck);
201
202
203
204 FileStatus randomFile = mockStoreFile(UUID.randomUUID().toString());
205 allStoreFiles.add(randomFile);
206 deletableFiles = cache.getUnreferencedFiles(allStoreFiles);
207 assertEquals(randomFile, Iterables.getOnlyElement(deletableFiles));
208 assertEquals(1, count.get() - countBeforeCheck);
209 }
210
211 private List<FileStatus> getStoreFilesForSnapshot(SnapshotMock.SnapshotBuilder builder)
212 throws IOException {
213 final List<FileStatus> allStoreFiles = Lists.newArrayList();
214 SnapshotReferenceUtil
215 .visitReferencedFiles(UTIL.getConfiguration(), fs, builder.getSnapshotsDir(),
216 new SnapshotReferenceUtil.SnapshotVisitor() {
217 @Override public void logFile(String server, String logfile) throws IOException {
218
219 }
220
221 @Override public void storeFile(HRegionInfo regionInfo, String familyName,
222 SnapshotProtos.SnapshotRegionManifest.StoreFile storeFile) throws IOException {
223 FileStatus status = mockStoreFile(storeFile.getName());
224 allStoreFiles.add(status);
225 }
226 });
227 return allStoreFiles;
228 }
229
230 private FileStatus mockStoreFile(String storeFileName) {
231 FileStatus status = mock(FileStatus.class);
232 Path path = mock(Path.class);
233 when(path.getName()).thenReturn(storeFileName);
234 when(status.getPath()).thenReturn(path);
235 return status;
236 }
237
238 class SnapshotFiles implements SnapshotFileCache.SnapshotFileInspector {
239 public Collection<String> filesUnderSnapshot(final Path snapshotDir) throws IOException {
240 Collection<String> files = new HashSet<String>();
241 files.addAll(SnapshotReferenceUtil.getWALNames(fs, snapshotDir));
242 files.addAll(SnapshotReferenceUtil.getHFileNames(UTIL.getConfiguration(), fs, snapshotDir));
243 return files;
244 }
245 };
246
247 private SnapshotMock.SnapshotBuilder createAndTestSnapshotV1(final SnapshotFileCache cache,
248 final String name, final boolean tmp, final boolean removeOnExit) throws IOException {
249 SnapshotMock snapshotMock = new SnapshotMock(UTIL.getConfiguration(), fs, rootDir);
250 SnapshotMock.SnapshotBuilder builder = snapshotMock.createSnapshotV1(name, name);
251 createAndTestSnapshot(cache, builder, tmp, removeOnExit);
252 return builder;
253 }
254
255 private void createAndTestSnapshotV2(final SnapshotFileCache cache, final String name,
256 final boolean tmp, final boolean removeOnExit) throws IOException {
257 SnapshotMock snapshotMock = new SnapshotMock(UTIL.getConfiguration(), fs, rootDir);
258 SnapshotMock.SnapshotBuilder builder = snapshotMock.createSnapshotV2(name, name);
259 createAndTestSnapshot(cache, builder, tmp, removeOnExit);
260 }
261
262 private void createAndTestSnapshot(final SnapshotFileCache cache,
263 final SnapshotMock.SnapshotBuilder builder,
264 final boolean tmp, final boolean removeOnExit) throws IOException {
265 List<Path> files = new ArrayList<Path>();
266 for (int i = 0; i < 3; ++i) {
267 for (Path filePath: builder.addRegion()) {
268 String fileName = filePath.getName();
269 if (tmp) {
270
271 FSUtils.logFileSystemState(fs, rootDir, LOG);
272 Iterable<FileStatus> nonSnapshot = getNonSnapshotFiles(cache, filePath);
273 assertFalse("Cache didn't find " + fileName, Iterables.contains(nonSnapshot, fileName));
274 }
275 files.add(filePath);
276 }
277 }
278
279
280 if (!tmp) {
281 builder.commit();
282 }
283
284
285 for (Path path: files) {
286 Iterable<FileStatus> nonSnapshotFiles = getNonSnapshotFiles(cache, path);
287 assertFalse("Cache didn't find " + path.getName(),
288 Iterables.contains(nonSnapshotFiles, path.getName()));
289 }
290
291 FSUtils.logFileSystemState(fs, rootDir, LOG);
292 if (removeOnExit) {
293 LOG.debug("Deleting snapshot.");
294 fs.delete(builder.getSnapshotsDir(), true);
295 FSUtils.logFileSystemState(fs, rootDir, LOG);
296
297
298 for (Path filePath: files) {
299 Iterable<FileStatus> nonSnapshotFiles = getNonSnapshotFiles(cache, filePath);
300 assertFalse("Cache didn't find " + filePath.getName(), Iterables.contains(nonSnapshotFiles,
301 filePath.getName()));
302 }
303
304
305 cache.triggerCacheRefreshForTesting();
306
307 for (Path filePath: files) {
308 Iterable<FileStatus> nonSnapshotFiles = getNonSnapshotFiles(cache, filePath);
309 assertTrue("Cache found '" + filePath.getName() + "', but it shouldn't have.",
310 !Iterables.contains(nonSnapshotFiles, filePath.getName()));
311 }
312 }
313 }
314
315 private Iterable<FileStatus> getNonSnapshotFiles(SnapshotFileCache cache, Path storeFile)
316 throws IOException {
317 return cache.getUnreferencedFiles(
318 Arrays.asList(FSUtils.listStatus(fs, storeFile.getParent()))
319 );
320 }
321 }