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.master.snapshot; 019 020import java.io.IOException; 021import java.util.HashSet; 022import java.util.List; 023import java.util.Set; 024import java.util.concurrent.ThreadPoolExecutor; 025import org.apache.hadoop.hbase.ServerName; 026import org.apache.hadoop.hbase.client.RegionInfo; 027import org.apache.hadoop.hbase.client.RegionReplicaUtil; 028import org.apache.hadoop.hbase.errorhandling.ForeignException; 029import org.apache.hadoop.hbase.master.MasterServices; 030import org.apache.hadoop.hbase.mob.MobUtils; 031import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils; 032import org.apache.hadoop.hbase.snapshot.SnapshotManifest; 033import org.apache.hadoop.hbase.util.CommonFSUtils; 034import org.apache.hadoop.hbase.util.ModifyRegionUtils; 035import org.apache.hadoop.hbase.util.Pair; 036import org.apache.yetus.audience.InterfaceAudience; 037import org.apache.yetus.audience.InterfaceStability; 038import org.apache.zookeeper.KeeperException; 039import org.slf4j.Logger; 040import org.slf4j.LoggerFactory; 041 042import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription; 043 044/** 045 * Take a snapshot of a disabled table. 046 * <p> 047 * Table must exist when taking the snapshot, or results are undefined. 048 */ 049@InterfaceAudience.Private 050@InterfaceStability.Evolving 051public class DisabledTableSnapshotHandler extends TakeSnapshotHandler { 052 private static final Logger LOG = LoggerFactory.getLogger(DisabledTableSnapshotHandler.class); 053 054 /** 055 * @param snapshot descriptor of the snapshot to take 056 * @param masterServices master services provider 057 * @throws IOException if it cannot access the filesystem of the snapshot 058 * temporary directory 059 */ 060 public DisabledTableSnapshotHandler(SnapshotDescription snapshot, 061 final MasterServices masterServices, final SnapshotManager snapshotManager) 062 throws IOException { 063 super(snapshot, masterServices, snapshotManager); 064 } 065 066 @Override 067 public DisabledTableSnapshotHandler prepare() throws Exception { 068 return (DisabledTableSnapshotHandler) super.prepare(); 069 } 070 071 // TODO consider parallelizing these operations since they are independent. Right now its just 072 // easier to keep them serial though 073 @Override 074 public void snapshotRegions(List<Pair<RegionInfo, ServerName>> regionsAndLocations) 075 throws IOException, KeeperException { 076 try { 077 // 1. get all the regions hosting this table. 078 079 // extract each pair to separate lists 080 Set<RegionInfo> regions = new HashSet<>(); 081 for (Pair<RegionInfo, ServerName> p : regionsAndLocations) { 082 // Don't include non-default regions 083 RegionInfo hri = p.getFirst(); 084 if (RegionReplicaUtil.isDefaultReplica(hri)) { 085 regions.add(hri); 086 } 087 } 088 // handle the mob files if any. 089 boolean mobEnabled = MobUtils.hasMobColumns(htd); 090 if (mobEnabled) { 091 // snapshot the mob files as a offline region. 092 RegionInfo mobRegionInfo = MobUtils.getMobRegionInfo(htd.getTableName()); 093 regions.add(mobRegionInfo); 094 } 095 096 // 2. for each region, write all the info to disk 097 String msg = "Starting to write region info and WALs for regions for offline snapshot:" 098 + ClientSnapshotDescriptionUtils.toString(snapshot); 099 LOG.info(msg); 100 status.setStatus(msg); 101 102 ThreadPoolExecutor exec = SnapshotManifest.createExecutor(conf, "DisabledTableSnapshot"); 103 try { 104 ModifyRegionUtils.editRegions(exec, regions, new ModifyRegionUtils.RegionEditTask() { 105 @Override 106 public void editRegion(final RegionInfo regionInfo) throws IOException { 107 snapshotManifest.addRegion(CommonFSUtils.getTableDir(rootDir, snapshotTable), 108 regionInfo); 109 } 110 }); 111 } finally { 112 exec.shutdown(); 113 } 114 } catch (Exception e) { 115 // make sure we capture the exception to propagate back to the client later 116 String reason = "Failed snapshot " + ClientSnapshotDescriptionUtils.toString(snapshot) 117 + " due to exception:" + e.getMessage(); 118 ForeignException ee = new ForeignException(reason, e); 119 monitor.receive(ee); 120 status.abort("Snapshot of table: "+ snapshotTable + " failed because " + e.getMessage()); 121 } finally { 122 LOG.debug("Marking snapshot" + ClientSnapshotDescriptionUtils.toString(snapshot) 123 + " as finished."); 124 } 125 } 126 127 @Override 128 protected boolean downgradeToSharedTableLock() { 129 // for taking snapshot on disabled table, it is OK to always hold the exclusive lock, as we do 130 // not need to assign the regions when there are region server crashes. 131 return false; 132 } 133}