View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.master.snapshot;
19  
20  import static org.junit.Assert.assertFalse;
21  import static org.junit.Assert.assertTrue;
22  
23  import java.io.IOException;
24  import java.util.*;
25  
26  import com.google.common.collect.Iterables;
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.fs.FileStatus;
30  import org.apache.hadoop.fs.FileSystem;
31  import org.apache.hadoop.fs.Path;
32  import org.apache.hadoop.hbase.HBaseTestingUtility;
33  import org.apache.hadoop.hbase.testclassification.MediumTests;
34  import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
35  import org.apache.hadoop.hbase.snapshot.SnapshotReferenceUtil;
36  import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils.SnapshotMock;
37  import org.apache.hadoop.hbase.util.FSUtils;
38  import org.junit.After;
39  import org.junit.AfterClass;
40  import org.junit.BeforeClass;
41  import org.junit.Ignore;
42  import org.junit.Test;
43  import org.junit.experimental.categories.Category;
44  
45  /**
46   * Test that we correctly reload the cache, filter directories, etc.
47   */
48  @Category(MediumTests.class)
49  public class TestSnapshotFileCache {
50  
51    private static final Log LOG = LogFactory.getLog(TestSnapshotFileCache.class);
52    private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
53    private static long sequenceId = 0;
54    private static FileSystem fs;
55    private static Path rootDir;
56  
57    @BeforeClass
58    public static void startCluster() throws Exception {
59      UTIL.startMiniDFSCluster(1);
60      fs = UTIL.getDFSCluster().getFileSystem();
61      rootDir = UTIL.getDefaultRootDirPath();
62    }
63  
64    @AfterClass
65    public static void stopCluster() throws Exception {
66      UTIL.shutdownMiniDFSCluster();
67    }
68  
69    @After
70    public void cleanupFiles() throws Exception {
71      // cleanup the snapshot directory
72      Path snapshotDir = SnapshotDescriptionUtils.getSnapshotsDir(rootDir);
73      fs.delete(snapshotDir, true);
74    }
75  
76    @Test(timeout = 10000000)
77    @Ignore("See HBASE-19275")
78    public void testLoadAndDelete() throws IOException {
79      // don't refresh the cache unless we tell it to
80      long period = Long.MAX_VALUE;
81      SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, period, 10000000,
82          "test-snapshot-file-cache-refresh", new SnapshotFiles());
83  
84      createAndTestSnapshotV1(cache, "snapshot1a", false, true);
85  
86      createAndTestSnapshotV2(cache, "snapshot2a", false, true);
87    }
88  
89    @Test
90    @Ignore("See HBASE-19275")
91    public void testReloadModifiedDirectory() throws IOException {
92      // don't refresh the cache unless we tell it to
93      long period = Long.MAX_VALUE;
94      SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, period, 10000000,
95          "test-snapshot-file-cache-refresh", new SnapshotFiles());
96  
97      createAndTestSnapshotV1(cache, "snapshot1", false, true);
98      // now delete the snapshot and add a file with a different name
99      createAndTestSnapshotV1(cache, "snapshot1", false, false);
100 
101     createAndTestSnapshotV2(cache, "snapshot2", false, true);
102     // now delete the snapshot and add a file with a different name
103     createAndTestSnapshotV2(cache, "snapshot2", false, false);
104   }
105 
106   @Test
107   public void testSnapshotTempDirReload() throws IOException {
108     long period = Long.MAX_VALUE;
109     // This doesn't refresh cache until we invoke it explicitly
110     SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, period, 10000000,
111         "test-snapshot-file-cache-refresh", new SnapshotFiles());
112 
113     // Add a new non-tmp snapshot
114     createAndTestSnapshotV1(cache, "snapshot0v1", false, false);
115     createAndTestSnapshotV1(cache, "snapshot0v2", false, false);
116   }
117 
118   class SnapshotFiles implements SnapshotFileCache.SnapshotFileInspector {
119     public Collection<String> filesUnderSnapshot(final Path snapshotDir) throws IOException {
120       Collection<String> files =  new HashSet<String>();
121       files.addAll(SnapshotReferenceUtil.getHFileNames(UTIL.getConfiguration(), fs, snapshotDir));
122       return files;
123     }
124   };
125 
126   private SnapshotMock.SnapshotBuilder createAndTestSnapshotV1(final SnapshotFileCache cache,
127       final String name, final boolean tmp, final boolean removeOnExit) throws IOException {
128     SnapshotMock snapshotMock = new SnapshotMock(UTIL.getConfiguration(), fs, rootDir);
129     SnapshotMock.SnapshotBuilder builder = snapshotMock.createSnapshotV1(name, name);
130     createAndTestSnapshot(cache, builder, tmp, removeOnExit);
131     return builder;
132   }
133 
134   private void createAndTestSnapshotV2(final SnapshotFileCache cache, final String name,
135       final boolean tmp, final boolean removeOnExit) throws IOException {
136     SnapshotMock snapshotMock = new SnapshotMock(UTIL.getConfiguration(), fs, rootDir);
137     SnapshotMock.SnapshotBuilder builder = snapshotMock.createSnapshotV2(name, name);
138     createAndTestSnapshot(cache, builder, tmp, removeOnExit);
139   }
140 
141   private void createAndTestSnapshot(final SnapshotFileCache cache,
142       final SnapshotMock.SnapshotBuilder builder,
143       final boolean tmp, final boolean removeOnExit) throws IOException {
144     List<Path> files = new ArrayList<Path>();
145     for (int i = 0; i < 3; ++i) {
146       for (Path filePath: builder.addRegion()) {
147         files.add(filePath);
148       }
149     }
150 
151     // Finalize the snapshot
152     builder.commit();
153 
154     // Make sure that all files are still present
155     for (Path path: files) {
156       Iterable<FileStatus> nonSnapshotFiles = getNonSnapshotFiles(cache, path);
157       assertFalse("Cache didn't find " + path.getName(),
158           Iterables.contains(nonSnapshotFiles, path.getName()));
159     }
160 
161     FSUtils.logFileSystemState(fs, rootDir, LOG);
162     if (removeOnExit) {
163       LOG.debug("Deleting snapshot.");
164       fs.delete(builder.getSnapshotsDir(), true);
165       FSUtils.logFileSystemState(fs, rootDir, LOG);
166 
167       // The files should be in cache until next refresh
168       for (Path filePath: files) {
169         Iterable<FileStatus> nonSnapshotFiles = getNonSnapshotFiles(cache, filePath);
170         assertFalse("Cache didn't find " + filePath.getName(), Iterables.contains(nonSnapshotFiles,
171             filePath.getName()));
172       }
173 
174       // then trigger a refresh
175       cache.triggerCacheRefreshForTesting();
176 
177       // and not it shouldn't find those files
178       for (Path filePath: files) {
179         Iterable<FileStatus> nonSnapshotFiles = getNonSnapshotFiles(cache, filePath);
180         assertTrue("Cache found '" + filePath.getName() + "', but it shouldn't have.",
181             !Iterables.contains(nonSnapshotFiles, filePath.getName()));
182       }
183     }
184   }
185 
186   private Iterable<FileStatus> getNonSnapshotFiles(SnapshotFileCache cache, Path storeFile)
187       throws IOException {
188     return cache.getUnreferencedFiles(
189         Arrays.asList(FSUtils.listStatus(fs, storeFile.getParent())), null
190     );
191   }
192 }