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