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