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  
19  package org.apache.hadoop.hbase.snapshot;
20  
21  import com.google.protobuf.CodedInputStream;
22  import com.google.protobuf.InvalidProtocolBufferException;
23  import java.io.IOException;
24  import java.io.InterruptedIOException;
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.concurrent.Callable;
28  import java.util.concurrent.Executor;
29  import java.util.concurrent.ExecutionException;
30  import java.util.concurrent.ExecutorCompletionService;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.hadoop.hbase.classification.InterfaceAudience;
35  import org.apache.hadoop.conf.Configuration;
36  import org.apache.hadoop.fs.FSDataInputStream;
37  import org.apache.hadoop.fs.FSDataOutputStream;
38  import org.apache.hadoop.fs.FileStatus;
39  import org.apache.hadoop.fs.FileSystem;
40  import org.apache.hadoop.fs.Path;
41  import org.apache.hadoop.fs.PathFilter;
42  import org.apache.hadoop.hbase.HRegionInfo;
43  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
44  import org.apache.hadoop.hbase.protobuf.generated.SnapshotProtos.SnapshotRegionManifest;
45  import org.apache.hadoop.hbase.regionserver.StoreFileInfo;
46  import org.apache.hadoop.hbase.util.ByteStringer;
47  import org.apache.hadoop.hbase.util.FSUtils;
48  
49  /**
50   * DO NOT USE DIRECTLY. USE {@link SnapshotManifest}.
51   *
52   * Snapshot v2 layout format
53   *  - Single Manifest file containing all the information of regions
54   *  - In the online-snapshot case each region will write a "region manifest"
55   *      /snapshotName/manifest.regionName
56   */
57  @InterfaceAudience.Private
58  public final class SnapshotManifestV2 {
59    private static final Log LOG = LogFactory.getLog(SnapshotManifestV2.class);
60  
61    public static final int DESCRIPTOR_VERSION = 2;
62  
63    public static final String SNAPSHOT_MANIFEST_PREFIX = "region-manifest.";
64  
65    private SnapshotManifestV2() {}
66  
67    static class ManifestBuilder implements SnapshotManifest.RegionVisitor<
68                      SnapshotRegionManifest.Builder, SnapshotRegionManifest.FamilyFiles.Builder> {
69      private final Configuration conf;
70      private final Path snapshotDir;
71      private final FileSystem rootFs;
72  
73      public ManifestBuilder(final Configuration conf, final FileSystem rootFs,
74          final Path snapshotDir) {
75        this.snapshotDir = snapshotDir;
76        this.conf = conf;
77        this.rootFs = rootFs;
78      }
79  
80      public SnapshotRegionManifest.Builder regionOpen(final HRegionInfo regionInfo) {
81        SnapshotRegionManifest.Builder manifest = SnapshotRegionManifest.newBuilder();
82        manifest.setRegionInfo(HRegionInfo.convert(regionInfo));
83        return manifest;
84      }
85  
86      public void regionClose(final SnapshotRegionManifest.Builder region) throws IOException {
87        // we should ensure the snapshot dir exist, maybe it has been deleted by master
88        // see HBASE-16464
89        FileSystem workingDirFs = snapshotDir.getFileSystem(this.conf);
90        if (workingDirFs.exists(snapshotDir)) {
91          SnapshotRegionManifest manifest = region.build();
92          FSDataOutputStream stream = workingDirFs.create(
93              getRegionManifestPath(snapshotDir, manifest));
94          try {
95            manifest.writeTo(stream);
96          } finally {
97            stream.close();
98          }
99        } else {
100         LOG.warn("can't write manifest without parent dir, maybe it has been deleted by master?");
101       }
102     }
103 
104     public SnapshotRegionManifest.FamilyFiles.Builder familyOpen(
105         final SnapshotRegionManifest.Builder region, final byte[] familyName) {
106       SnapshotRegionManifest.FamilyFiles.Builder family =
107           SnapshotRegionManifest.FamilyFiles.newBuilder();
108       family.setFamilyName(ByteStringer.wrap(familyName));
109       return family;
110     }
111 
112     public void familyClose(final SnapshotRegionManifest.Builder region,
113         final SnapshotRegionManifest.FamilyFiles.Builder family) {
114       region.addFamilyFiles(family.build());
115     }
116 
117     public void storeFile(final SnapshotRegionManifest.Builder region,
118         final SnapshotRegionManifest.FamilyFiles.Builder family, final StoreFileInfo storeFile)
119         throws IOException {
120       SnapshotRegionManifest.StoreFile.Builder sfManifest =
121             SnapshotRegionManifest.StoreFile.newBuilder();
122       sfManifest.setName(storeFile.getPath().getName());
123       if (storeFile.isReference()) {
124         sfManifest.setReference(storeFile.getReference().convert());
125       }
126       sfManifest.setFileSize(storeFile.getReferencedFileStatus(rootFs).getLen());
127       family.addStoreFiles(sfManifest.build());
128     }
129   }
130 
131   static List<SnapshotRegionManifest> loadRegionManifests(final Configuration conf,
132       final Executor executor, final FileSystem fs, final Path snapshotDir,
133       final SnapshotDescription desc, final int manifestSizeLimit) throws IOException {
134     FileStatus[] manifestFiles = FSUtils.listStatus(fs, snapshotDir, new PathFilter() {
135       @Override
136       public boolean accept(Path path) {
137         return path.getName().startsWith(SNAPSHOT_MANIFEST_PREFIX);
138       }
139     });
140 
141     if (manifestFiles == null || manifestFiles.length == 0) return null;
142 
143     final ExecutorCompletionService<SnapshotRegionManifest> completionService =
144       new ExecutorCompletionService<SnapshotRegionManifest>(executor);
145     for (final FileStatus st: manifestFiles) {
146       completionService.submit(new Callable<SnapshotRegionManifest>() {
147         @Override
148         public SnapshotRegionManifest call() throws IOException {
149           FSDataInputStream stream = fs.open(st.getPath());
150           CodedInputStream cin = CodedInputStream.newInstance(stream);
151           cin.setSizeLimit(manifestSizeLimit);
152 
153           try {
154             return SnapshotRegionManifest.parseFrom(cin);
155           } finally {
156             stream.close();
157           }
158         }
159       });
160     }
161 
162     ArrayList<SnapshotRegionManifest> regionsManifest =
163         new ArrayList<SnapshotRegionManifest>(manifestFiles.length);
164     try {
165       for (int i = 0; i < manifestFiles.length; ++i) {
166         regionsManifest.add(completionService.take().get());
167       }
168     } catch (InterruptedException e) {
169       throw new InterruptedIOException(e.getMessage());
170     } catch (ExecutionException e) {
171       Throwable t = e.getCause();
172 
173       if(t instanceof InvalidProtocolBufferException) {
174         throw (InvalidProtocolBufferException)t;
175       } else {
176         throw new IOException("ExecutionException", e.getCause());
177       }
178     }
179     return regionsManifest;
180   }
181 
182   static void deleteRegionManifest(final FileSystem fs, final Path snapshotDir,
183       final SnapshotRegionManifest manifest) throws IOException {
184     fs.delete(getRegionManifestPath(snapshotDir, manifest), true);
185   }
186 
187   private static Path getRegionManifestPath(final Path snapshotDir,
188       final SnapshotRegionManifest manifest) {
189     String regionName = SnapshotManifest.getRegionNameFromManifest(manifest);
190     return new Path(snapshotDir, SNAPSHOT_MANIFEST_PREFIX + regionName);
191   }
192 }