001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.regionserver; 019 020import java.io.IOException; 021import java.util.Map; 022import java.util.concurrent.ExecutionException; 023import java.util.concurrent.TimeUnit; 024import org.apache.hadoop.conf.Configuration; 025import org.apache.hadoop.fs.FileSystem; 026import org.apache.hadoop.fs.Path; 027import org.apache.hadoop.hbase.client.RegionInfo; 028import org.apache.hadoop.hbase.snapshot.CorruptedSnapshotException; 029import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils; 030import org.apache.hadoop.hbase.snapshot.SnapshotManifest; 031import org.apache.hadoop.hbase.snapshot.SnapshotReferenceUtil; 032import org.apache.hadoop.hbase.snapshot.SnapshotReferenceUtil.StoreFileVisitor; 033import org.apache.hadoop.hbase.util.CommonFSUtils; 034import org.apache.hadoop.hbase.util.Pair; 035import org.apache.yetus.audience.InterfaceAudience; 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038 039import org.apache.hbase.thirdparty.com.google.common.cache.CacheBuilder; 040import org.apache.hbase.thirdparty.com.google.common.cache.CacheLoader; 041import org.apache.hbase.thirdparty.com.google.common.cache.LoadingCache; 042 043import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 044import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription; 045import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotRegionManifest; 046import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotRegionManifest.StoreFile; 047 048/** 049 * Used by {@link org.apache.hadoop.hbase.master.procedure.SnapshotVerifyProcedure} to verify if the 050 * region info and store file info in RegionManifest are intact. 051 */ 052@InterfaceAudience.Private 053public class RSSnapshotVerifier { 054 private static final Logger LOG = LoggerFactory.getLogger(RSSnapshotVerifier.class); 055 056 private final LoadingCache<SnapshotDescription, 057 Pair<FileSystem, Map<String, SnapshotRegionManifest>>> SNAPSHOT_MANIFEST_CACHE; 058 private final Configuration conf; 059 060 public RSSnapshotVerifier(Configuration conf) { 061 this.conf = conf; 062 long expiredTime = conf.getLong("hbase.snapshot-manifest.cache.expired.sec", 600); 063 long maxSize = conf.getLong("hbase.snapshot-manifest.cache.max.size", 10); 064 this.SNAPSHOT_MANIFEST_CACHE = 065 CacheBuilder.newBuilder().expireAfterAccess(expiredTime, TimeUnit.SECONDS) 066 .maximumSize(maxSize).build(new SnapshotManifestCacheLoader(conf)); 067 } 068 069 public void verifyRegion(SnapshotDescription snapshot, RegionInfo region) throws IOException { 070 try { 071 Pair<FileSystem, Map<String, SnapshotRegionManifest>> cache = 072 SNAPSHOT_MANIFEST_CACHE.get(snapshot); 073 Map<String, SnapshotRegionManifest> rmMap = cache.getSecond(); 074 if (rmMap == null) { 075 throw new CorruptedSnapshotException(snapshot.getName() + "looks empty"); 076 } 077 SnapshotRegionManifest regionManifest = rmMap.get(region.getEncodedName()); 078 if (regionManifest == null) { 079 LOG.warn("No snapshot region directory found for {}", region.getRegionNameAsString()); 080 return; 081 } 082 // verify region info 083 RegionInfo manifestRegionInfo = ProtobufUtil.toRegionInfo(regionManifest.getRegionInfo()); 084 if (RegionInfo.COMPARATOR.compare(region, manifestRegionInfo) != 0) { 085 String msg = 086 "Manifest region info " + manifestRegionInfo + "doesn't match expected region:" + region; 087 throw new CorruptedSnapshotException(msg, ProtobufUtil.createSnapshotDesc(snapshot)); 088 } 089 // verify store file 090 SnapshotReferenceUtil.visitRegionStoreFiles(regionManifest, new StoreFileVisitor() { 091 @Override 092 public void storeFile(RegionInfo region, String familyName, StoreFile storeFile) 093 throws IOException { 094 SnapshotReferenceUtil.verifyStoreFile(conf, cache.getFirst(), /* snapshotDir= */ null, // snapshotDir 095 // is 096 // never 097 // used, 098 // so 099 // it's 100 // ok 101 // to 102 // pass 103 // null 104 // here. 105 // maybe 106 // we 107 // can 108 // remove 109 // this 110 // parameter 111 // later. 112 snapshot, region, familyName, storeFile); 113 } 114 }); 115 } catch (ExecutionException e) { 116 if (e.getCause() instanceof CorruptedSnapshotException) { 117 throw new CorruptedSnapshotException(e.getCause().getMessage(), 118 ProtobufUtil.createSnapshotDesc(snapshot)); 119 } else { 120 LOG.error("Failed loading snapshot manifest for {} from filesystem", snapshot.getName(), 121 e.getCause()); 122 throw new IOException(e.getCause()); 123 } 124 } 125 } 126 127 // to avoid loading snapshot manifest from filesystem for each region, try to cache it here 128 private static final class SnapshotManifestCacheLoader extends 129 CacheLoader<SnapshotDescription, Pair<FileSystem, Map<String, SnapshotRegionManifest>>> { 130 private final Configuration conf; 131 132 private SnapshotManifestCacheLoader(Configuration conf) { 133 this.conf = conf; 134 } 135 136 @Override 137 public Pair<FileSystem, Map<String, SnapshotRegionManifest>> load(SnapshotDescription snapshot) 138 throws Exception { 139 Path rootDir = CommonFSUtils.getRootDir(conf); 140 Path workingDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(snapshot, rootDir, conf); 141 FileSystem rootFs = CommonFSUtils.getRootDirFileSystem(conf); 142 FileSystem workingDirFS = workingDir.getFileSystem(conf); 143 SnapshotManifest manifest = SnapshotManifest.open(conf, workingDirFS, workingDir, snapshot); 144 LOG.debug("loading snapshot manifest for {} from {}", snapshot.getName(), workingDir); 145 return Pair.newPair(rootFs, manifest.getRegionManifestsMap()); 146 } 147 } 148}