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  
22  import java.io.IOException;
23  import java.util.*;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
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.HBaseTestingUtility;
31  import org.apache.hadoop.hbase.testclassification.MediumTests;
32  import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
33  import org.apache.hadoop.hbase.snapshot.SnapshotReferenceUtil;
34  import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils.SnapshotMock;
35  import org.apache.hadoop.hbase.util.FSUtils;
36  import org.junit.After;
37  import org.junit.AfterClass;
38  import org.junit.BeforeClass;
39  import org.junit.Ignore;
40  import org.junit.Test;
41  import org.junit.experimental.categories.Category;
42  
43  /**
44   * Test that we correctly reload the cache, filter directories, etc.
45   */
46  @Category(MediumTests.class)
47  public class TestSnapshotFileCache {
48  
49    private static final Log LOG = LogFactory.getLog(TestSnapshotFileCache.class);
50    private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
51    // don't refresh the cache unless we tell it to
52    private static final long PERIOD = Long.MAX_VALUE;
53    private static FileSystem fs;
54    private static Path rootDir;
55    private static Path snapshotDir;
56  
57    @BeforeClass
58    public static void startCluster() throws Exception {
59      UTIL.startMiniDFSCluster(1);
60      fs = UTIL.getDFSCluster().getFileSystem();
61      rootDir = UTIL.getDefaultRootDirPath();
62      snapshotDir = SnapshotDescriptionUtils.getSnapshotsDir(rootDir);
63    }
64  
65    @AfterClass
66    public static void stopCluster() throws Exception {
67      UTIL.shutdownMiniDFSCluster();
68    }
69  
70    @After
71    public void cleanupFiles() throws Exception {
72      // cleanup the snapshot directory
73      fs.delete(snapshotDir, true);
74    }
75  
76    @Test(timeout = 10000000)
77    @Ignore("See HBASE-19275")
78    public void testLoadAndDelete() throws IOException {
79      SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, PERIOD, 10000000,
80          "test-snapshot-file-cache-refresh", new SnapshotFiles());
81  
82      createAndTestSnapshotV1(cache, "snapshot1a", false, true, false);
83  
84      createAndTestSnapshotV2(cache, "snapshot2a", false, true, false);
85    }
86  
87    @Test
88    @Ignore("See HBASE-19275")
89    public void testReloadModifiedDirectory() throws IOException {
90      SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, PERIOD, 10000000,
91          "test-snapshot-file-cache-refresh", new SnapshotFiles());
92  
93      createAndTestSnapshotV1(cache, "snapshot1", false, true, false);
94      // now delete the snapshot and add a file with a different name
95      createAndTestSnapshotV1(cache, "snapshot1", false, false, false);
96  
97      createAndTestSnapshotV2(cache, "snapshot2", false, true, false);
98      // now delete the snapshot and add a file with a different name
99      createAndTestSnapshotV2(cache, "snapshot2", false, false, false);
100   }
101 
102   @Test
103   public void testSnapshotTempDirReload() throws IOException {
104     SnapshotFileCache cache =
105         new SnapshotFileCache(fs, rootDir, PERIOD, 10000000, "test-snapshot-file-cache-refresh", new SnapshotFiles());
106 
107     // Add a new non-tmp snapshot
108     createAndTestSnapshotV1(cache, "snapshot0v1", false, false, false);
109     createAndTestSnapshotV1(cache, "snapshot0v2", false, false, false);
110   }
111 
112   @Test
113   public void testCacheUpdatedWhenLastModifiedOfSnapDirNotUpdated() throws IOException {
114     SnapshotFileCache cache = new SnapshotFileCache(fs, rootDir, PERIOD, 10000000,
115         "test-snapshot-file-cache-refresh", new SnapshotFiles());
116 
117     // Add a new non-tmp snapshot
118     createAndTestSnapshotV1(cache, "snapshot1v1", false, false, true);
119     createAndTestSnapshotV1(cache, "snapshot1v2", false, false, true);
120 
121     // Add a new tmp snapshot
122     createAndTestSnapshotV2(cache, "snapshot2v1", true, false, true);
123 
124     // Add another tmp snapshot
125     createAndTestSnapshotV2(cache, "snapshot2v2", true, false, true);
126   }
127 
128   class SnapshotFiles implements SnapshotFileCache.SnapshotFileInspector {
129     public Collection<String> filesUnderSnapshot(final Path snapshotDir) throws IOException {
130       Collection<String> files =  new HashSet<String>();
131       files.addAll(SnapshotReferenceUtil.getHFileNames(UTIL.getConfiguration(), fs, snapshotDir));
132       return files;
133     }
134   };
135 
136   private SnapshotMock.SnapshotBuilder createAndTestSnapshotV1(final SnapshotFileCache cache,
137       final String name, final boolean tmp, final boolean removeOnExit, boolean setFolderTime)
138       throws IOException {
139     SnapshotMock snapshotMock = new SnapshotMock(UTIL.getConfiguration(), fs, rootDir);
140     SnapshotMock.SnapshotBuilder builder = snapshotMock.createSnapshotV1(name, name);
141     createAndTestSnapshot(cache, builder, tmp, removeOnExit, setFolderTime);
142     return builder;
143   }
144 
145   private void createAndTestSnapshotV2(final SnapshotFileCache cache, final String name,
146       final boolean tmp, final boolean removeOnExit, boolean setFolderTime) throws IOException {
147     SnapshotMock snapshotMock = new SnapshotMock(UTIL.getConfiguration(), fs, rootDir);
148     SnapshotMock.SnapshotBuilder builder = snapshotMock.createSnapshotV2(name, name);
149     createAndTestSnapshot(cache, builder, tmp, removeOnExit, setFolderTime);
150   }
151 
152   private void createAndTestSnapshot(final SnapshotFileCache cache,
153       final SnapshotMock.SnapshotBuilder builder,
154       final boolean tmp, final boolean removeOnExit, boolean setFolderTime) throws IOException {
155     List<Path> files = new ArrayList<Path>();
156     for (int i = 0; i < 3; ++i) {
157       for (Path filePath: builder.addRegion()) {
158         files.add(filePath);
159       }
160     }
161 
162     // Finalize the snapshot
163     builder.commit();
164 
165     if (setFolderTime) {
166       fs.setTimes(snapshotDir, 0, -1);
167     }
168 
169     // Make sure that all files are still present
170     for (Path path: files) {
171       assertFalse("Cache didn't find " + path, contains(getNonSnapshotFiles(cache, path), path));
172     }
173 
174     FSUtils.logFileSystemState(fs, rootDir, LOG);
175     if (removeOnExit) {
176       LOG.debug("Deleting snapshot.");
177       fs.delete(builder.getSnapshotsDir(), true);
178       FSUtils.logFileSystemState(fs, rootDir, LOG);
179 
180       // The files should be in cache until next refresh
181       for (Path filePath: files) {
182         assertFalse("Cache didn't find " + filePath,
183           contains(getNonSnapshotFiles(cache, filePath), filePath));
184       }
185 
186       // then trigger a refresh
187       cache.triggerCacheRefreshForTesting();
188 
189       // and not it shouldn't find those files
190       for (Path filePath: files) {
191         assertFalse("Cache found '" + filePath + "', but it shouldn't have.",
192             contains(getNonSnapshotFiles(cache, filePath), filePath));
193       }
194     }
195   }
196 
197   private static boolean contains(Iterable<FileStatus> files, Path filePath) {
198     for (FileStatus status: files) {
199       if (filePath.equals(status.getPath())) {
200         return true;
201       }
202     }
203     return false;
204   }
205 
206   private static Iterable<FileStatus> getNonSnapshotFiles(SnapshotFileCache cache, Path storeFile)
207       throws IOException {
208     return cache.getUnreferencedFiles(
209         Arrays.asList(FSUtils.listStatus(fs, storeFile.getParent())), null
210     );
211   }
212 }