You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by mb...@apache.org on 2013/08/20 22:49:38 UTC
svn commit: r1515967 - in
/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase: io/
master/handler/ master/snapshot/ regionserver/ snapshot/
Author: mbertozzi
Date: Tue Aug 20 20:49:38 2013
New Revision: 1515967
URL: http://svn.apache.org/r1515967
Log:
HBASE-8760 possible loss of data in snapshot taken after region split
Modified:
hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/io/HFileLink.java
hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/handler/CreateTableHandler.java
hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/CloneSnapshotHandler.java
hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/DisabledTableSnapshotHandler.java
hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/EnabledTableSnapshotHandler.java
hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/MasterSnapshotVerifier.java
hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/RestoreSnapshotHandler.java
hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/TakeSnapshotHandler.java
hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java
hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/ExportSnapshot.java
hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/RestoreSnapshotHelper.java
hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotInfo.java
Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/io/HFileLink.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/io/HFileLink.java?rev=1515967&r1=1515966&r2=1515967&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/io/HFileLink.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/io/HFileLink.java Tue Aug 20 20:49:38 2013
@@ -109,6 +109,37 @@ public class HFileLink extends FileLink
}
/**
+ * Create an HFileLink relative path for the table/region/family/hfile location
+ * @param table Table name
+ * @param region Region Name
+ * @param family Family Name
+ * @param hfile HFile Name
+ * @return the relative Path to open the specified table/region/family/hfile link
+ */
+ public static Path createPath(final String table, final String region,
+ final String family, final String hfile) {
+ if (HFileLink.isHFileLink(hfile)) {
+ return new Path(family, hfile);
+ }
+ return new Path(family, HFileLink.createHFileLinkName(table, region, hfile));
+ }
+
+ /**
+ * Create an HFileLink instance from table/region/family/hfile location
+ * @param conf {@link Configuration} from which to extract specific archive locations
+ * @param table Table name
+ * @param region Region Name
+ * @param family Family Name
+ * @param hfile HFile Name
+ * @return Link to the file with the specified table/region/family/hfile location
+ * @throws IOException on unexpected error.
+ */
+ public static HFileLink create(final Configuration conf, final String table,
+ final String region, final String family, final String hfile) throws IOException {
+ return new HFileLink(conf, createPath(table, region, family, hfile));
+ }
+
+ /**
* @return the origin path of the hfile.
*/
public Path getOriginPath() {
@@ -130,7 +161,6 @@ public class HFileLink extends FileLink
return isHFileLink(path.getName());
}
-
/**
* @param fileName File name to check.
* @return True if the path is a HFileLink.
@@ -209,6 +239,15 @@ public class HFileLink extends FileLink
}
/**
+ * Returns true if the HFileLink exists
+ */
+ public boolean exists(final FileSystem fs) throws IOException {
+ return fs.exists(this.originPath) ||
+ fs.exists(this.tempPath) ||
+ fs.exists(this.archivePath);
+ }
+
+ /**
* Create a new HFileLink name
*
* @param hfileRegionInfo - Linked HFile Region Info
Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/handler/CreateTableHandler.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/handler/CreateTableHandler.java?rev=1515967&r1=1515966&r2=1515967&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/handler/CreateTableHandler.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/handler/CreateTableHandler.java Tue Aug 20 20:49:38 2013
@@ -188,7 +188,7 @@ public class CreateTableHandler extends
if (regionInfos != null && regionInfos.size() > 0) {
// 4. Add regions to META
- MetaEditor.addRegionsToMeta(this.catalogTracker, regionInfos);
+ addRegionsToMeta(this.catalogTracker, regionInfos);
// 5. Trigger immediate assignment of the regions in round-robin fashion
List<ServerName> servers = serverManager.getOnlineServersList();
@@ -225,4 +225,12 @@ public class CreateTableHandler extends
return ModifyRegionUtils.createRegions(conf, tableRootDir,
hTableDescriptor, newRegions, null);
}
+
+ /**
+ * Add the specified set of regions to the META table.
+ */
+ protected void addRegionsToMeta(final CatalogTracker ct, final List<HRegionInfo> regionInfos)
+ throws IOException {
+ MetaEditor.addRegionsToMeta(this.catalogTracker, regionInfos);
+ }
}
Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/CloneSnapshotHandler.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/CloneSnapshotHandler.java?rev=1515967&r1=1515966&r2=1515967&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/CloneSnapshotHandler.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/CloneSnapshotHandler.java Tue Aug 20 20:49:38 2013
@@ -33,6 +33,7 @@ import org.apache.hadoop.hbase.HTableDes
import org.apache.hadoop.hbase.NotAllMetaRegionsOnlineException;
import org.apache.hadoop.hbase.TableExistsException;
import org.apache.hadoop.hbase.catalog.MetaReader;
+import org.apache.hadoop.hbase.catalog.CatalogTracker;
import org.apache.hadoop.hbase.errorhandling.ForeignException;
import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher;
import org.apache.hadoop.hbase.master.MasterServices;
@@ -67,6 +68,8 @@ public class CloneSnapshotHandler extend
private final MasterMetrics metricsMaster;
private final MonitoredTask status;
+ private RestoreSnapshotHelper.RestoreMetaChanges metaChanges;
+
private volatile boolean stopped = false;
public CloneSnapshotHandler(final MasterServices masterServices,
@@ -106,7 +109,7 @@ public class CloneSnapshotHandler extend
Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshot, rootDir);
RestoreSnapshotHelper restoreHelper = new RestoreSnapshotHelper(conf, fs,
snapshot, snapshotDir, hTableDescriptor, tableDir, monitor, status);
- RestoreSnapshotHelper.RestoreMetaChanges metaChanges = restoreHelper.restoreHdfsRegions();
+ metaChanges = restoreHelper.restoreHdfsRegions();
// Clone operation should not have stuff to restore or remove
Preconditions.checkArgument(!metaChanges.hasRegionsToRestore(),
@@ -133,6 +136,13 @@ public class CloneSnapshotHandler extend
}
@Override
+ protected void addRegionsToMeta(final CatalogTracker ct, final List<HRegionInfo> regionInfos)
+ throws IOException {
+ super.addRegionsToMeta(ct, regionInfos);
+ metaChanges.updateMetaParentRegions(ct, regionInfos);
+ }
+
+ @Override
protected void completed(final Throwable exception) {
this.stopped = true;
if (exception != null) {
Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/DisabledTableSnapshotHandler.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/DisabledTableSnapshotHandler.java?rev=1515967&r1=1515966&r2=1515967&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/DisabledTableSnapshotHandler.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/DisabledTableSnapshotHandler.java Tue Aug 20 20:49:38 2013
@@ -37,8 +37,6 @@ import org.apache.hadoop.hbase.monitorin
import org.apache.hadoop.hbase.monitoring.TaskMonitor;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
import org.apache.hadoop.hbase.regionserver.HRegion;
-import org.apache.hadoop.hbase.snapshot.CopyRecoveredEditsTask;
-import org.apache.hadoop.hbase.snapshot.ReferenceRegionHFilesTask;
import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
import org.apache.hadoop.hbase.snapshot.TableInfoCopyTask;
import org.apache.hadoop.hbase.snapshot.TakeSnapshotUtils;
@@ -81,36 +79,16 @@ public class DisabledTableSnapshotHandle
// 1. get all the regions hosting this table.
// extract each pair to separate lists
- Set<String> serverNames = new HashSet<String>();
Set<HRegionInfo> regions = new HashSet<HRegionInfo>();
for (Pair<HRegionInfo, ServerName> p : regionsAndLocations) {
regions.add(p.getFirst());
- serverNames.add(p.getSecond().toString());
}
// 2. for each region, write all the info to disk
LOG.info("Starting to write region info and WALs for regions for offline snapshot:"
+ SnapshotDescriptionUtils.toString(snapshot));
for (HRegionInfo regionInfo : regions) {
- // 2.1 copy the regionInfo files to the snapshot
- Path snapshotRegionDir = TakeSnapshotUtils.getRegionSnapshotDirectory(snapshot, rootDir,
- regionInfo.getEncodedName());
- HRegion.writeRegioninfoOnFilesystem(regionInfo, snapshotRegionDir, fs, conf);
- // check for error for each region
- monitor.rethrowException();
-
- // 2.2 for each region, copy over its recovered.edits directory
- Path regionDir = HRegion.getRegionDir(rootDir, regionInfo);
- new CopyRecoveredEditsTask(snapshot, monitor, fs, regionDir, snapshotRegionDir).call();
- monitor.rethrowException();
- status.setStatus("Completed copying recovered edits for offline snapshot of table: "
- + snapshot.getTable());
-
- // 2.3 reference all the files in the region
- new ReferenceRegionHFilesTask(snapshot, monitor, regionDir, fs, snapshotRegionDir).call();
- monitor.rethrowException();
- status.setStatus("Completed referencing HFiles for offline snapshot of table: " +
- snapshot.getTable());
+ snapshotDisabledRegion(regionInfo);
}
// 3. write the table info to disk
Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/EnabledTableSnapshotHandler.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/EnabledTableSnapshotHandler.java?rev=1515967&r1=1515966&r2=1515967&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/EnabledTableSnapshotHandler.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/EnabledTableSnapshotHandler.java Tue Aug 20 20:49:38 2013
@@ -25,6 +25,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.errorhandling.ForeignException;
@@ -33,7 +34,9 @@ import org.apache.hadoop.hbase.master.me
import org.apache.hadoop.hbase.procedure.Procedure;
import org.apache.hadoop.hbase.procedure.ProcedureCoordinator;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
+import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.snapshot.HBaseSnapshotException;
+import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
import org.apache.hadoop.hbase.util.Pair;
import com.google.common.collect.Lists;
@@ -65,10 +68,14 @@ public class EnabledTableSnapshotHandler
*/
@Override
protected void snapshotRegions(List<Pair<HRegionInfo, ServerName>> regions)
- throws HBaseSnapshotException {
+ throws HBaseSnapshotException, IOException {
Set<String> regionServers = new HashSet<String>(regions.size());
for (Pair<HRegionInfo, ServerName> region : regions) {
- regionServers.add(region.getSecond().toString());
+ if (region != null && region.getFirst() != null && region.getSecond() != null) {
+ HRegionInfo hri = region.getFirst();
+ if (hri.isOffline() && (hri.isSplit() || hri.isSplitParent())) continue;
+ regionServers.add(region.getSecond().toString());
+ }
}
// start the snapshot on the RS
@@ -85,7 +92,19 @@ public class EnabledTableSnapshotHandler
// wait for the snapshot to complete. A timer thread is kicked off that should cancel this
// if it takes too long.
proc.waitForCompleted();
- LOG.info("Done waiting - snapshot for " + this.snapshot.getName() + " finished!");
+ LOG.info("Done waiting - online snapshot for " + this.snapshot.getName());
+
+ // Take the offline regions as disabled
+ Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(snapshot, rootDir);
+ for (Pair<HRegionInfo, ServerName> region : regions) {
+ HRegionInfo regionInfo = region.getFirst();
+ if (regionInfo.isOffline() && (regionInfo.isSplit() || regionInfo.isSplitParent())) {
+ if (!fs.exists(new Path(snapshotDir, regionInfo.getEncodedName()))) {
+ LOG.info("Take disabled snapshot of offline region=" + regionInfo);
+ snapshotDisabledRegion(regionInfo);
+ }
+ }
+ }
} catch (InterruptedException e) {
ForeignException ee =
new ForeignException("Interrupted while waiting for snapshot to finish", e);
Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/MasterSnapshotVerifier.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/MasterSnapshotVerifier.java?rev=1515967&r1=1515966&r2=1515967&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/MasterSnapshotVerifier.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/MasterSnapshotVerifier.java Tue Aug 20 20:49:38 2013
@@ -21,6 +21,8 @@ import java.io.IOException;
import java.util.List;
import java.util.Set;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.fs.FSDataInputStream;
@@ -32,6 +34,7 @@ import org.apache.hadoop.hbase.HConstant
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.catalog.MetaReader;
+import org.apache.hadoop.hbase.io.HFileLink;
import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription.Type;
@@ -39,10 +42,12 @@ import org.apache.hadoop.hbase.regionser
import org.apache.hadoop.hbase.regionserver.StoreFile;
import org.apache.hadoop.hbase.snapshot.CorruptedSnapshotException;
import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
+import org.apache.hadoop.hbase.snapshot.SnapshotReferenceUtil;
import org.apache.hadoop.hbase.snapshot.TakeSnapshotUtils;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.FSTableDescriptors;
import org.apache.hadoop.hbase.util.FSUtils;
+import org.apache.hadoop.hbase.util.FSVisitor;
import org.apache.hadoop.hbase.util.HFileArchiveUtil;
/**
@@ -76,6 +81,7 @@ import org.apache.hadoop.hbase.util.HFil
@InterfaceAudience.Private
@InterfaceStability.Unstable
public final class MasterSnapshotVerifier {
+ private static final Log LOG = LogFactory.getLog(MasterSnapshotVerifier.class);
private SnapshotDescription snapshot;
private FileSystem fs;
@@ -143,10 +149,28 @@ public final class MasterSnapshotVerifie
private void verifyRegions(Path snapshotDir) throws IOException {
List<HRegionInfo> regions = MetaReader.getTableRegions(this.services.getCatalogTracker(),
Bytes.toBytes(tableName));
+
+ Set<String> snapshotRegions = SnapshotReferenceUtil.getSnapshotRegionNames(fs, snapshotDir);
+ if (snapshotRegions == null) {
+ String msg = "Snapshot " + SnapshotDescriptionUtils.toString(snapshot) + " looks empty";
+ LOG.error(msg);
+ throw new CorruptedSnapshotException(msg);
+ }
+
+ if (snapshotRegions.size() != regions.size()) {
+ String msg = "Regions moved during the snapshot '" +
+ SnapshotDescriptionUtils.toString(snapshot) + "'. expected=" +
+ regions.size() + " snapshotted=" + snapshotRegions.size();
+ LOG.error(msg);
+ throw new CorruptedSnapshotException(msg);
+ }
+
for (HRegionInfo region : regions) {
- // if offline split parent, skip it
- if (region.isOffline() && (region.isSplit() || region.isSplitParent())) {
- continue;
+ if (!snapshotRegions.contains(region.getEncodedName())) {
+ // could happen due to a move or split race.
+ String msg = "No region directory found for region:" + region;
+ LOG.error(msg);
+ throw new CorruptedSnapshotException(msg, snapshot);
}
verifyRegion(fs, snapshotDir, region);
@@ -159,20 +183,18 @@ public final class MasterSnapshotVerifie
* @param snapshotDir snapshot directory to check
* @param region the region to check
*/
- private void verifyRegion(FileSystem fs, Path snapshotDir, HRegionInfo region) throws IOException {
+ private void verifyRegion(final FileSystem fs, final Path snapshotDir, final HRegionInfo region)
+ throws IOException {
// make sure we have region in the snapshot
Path regionDir = new Path(snapshotDir, region.getEncodedName());
- if (!fs.exists(regionDir)) {
- // could happen due to a move or split race.
- throw new CorruptedSnapshotException("No region directory found for region:" + region,
- snapshot);
- }
+
// make sure we have the region info in the snapshot
Path regionInfo = new Path(regionDir, HRegion.REGIONINFO_FILE);
// make sure the file exists
if (!fs.exists(regionInfo)) {
throw new CorruptedSnapshotException("No region info found for region:" + region, snapshot);
}
+
FSDataInputStream in = fs.open(regionInfo);
HRegionInfo found = new HRegionInfo();
try {
@@ -188,47 +210,45 @@ public final class MasterSnapshotVerifie
// make sure we have the expected recovered edits files
TakeSnapshotUtils.verifyRecoveredEdits(fs, snapshotDir, found, snapshot);
- // check for the existance of each hfile
- PathFilter familiesDirs = new FSUtils.FamilyDirFilter(fs);
- FileStatus[] columnFamilies = FSUtils.listStatus(fs, regionDir, familiesDirs);
- // should we do some checking here to make sure the cfs are correct?
- if (columnFamilies == null) return;
-
- // setup the suffixes for the snapshot directories
- Path tableNameSuffix = new Path(tableName);
- Path regionNameSuffix = new Path(tableNameSuffix, region.getEncodedName());
-
- // get the potential real paths
- Path archivedRegion = new Path(HFileArchiveUtil.getArchivePath(services.getConfiguration()),
- regionNameSuffix);
- Path realRegion = new Path(rootDir, regionNameSuffix);
-
- // loop through each cf and check we can find each of the hfiles
- for (FileStatus cf : columnFamilies) {
- FileStatus[] hfiles = FSUtils.listStatus(fs, cf.getPath(), null);
- // should we check if there should be hfiles?
- if (hfiles == null || hfiles.length == 0) continue;
-
- Path realCfDir = new Path(realRegion, cf.getPath().getName());
- Path archivedCfDir = new Path(archivedRegion, cf.getPath().getName());
- for (FileStatus hfile : hfiles) {
- // make sure the name is correct
- if (!StoreFile.validateStoreFileName(hfile.getPath().getName())) {
- throw new CorruptedSnapshotException("HFile: " + hfile.getPath()
- + " is not a valid hfile name.", snapshot);
- }
-
- // check to see if hfile is present in the real table
- String fileName = hfile.getPath().getName();
- Path file = new Path(realCfDir, fileName);
- Path archived = new Path(archivedCfDir, fileName);
- if (!fs.exists(file) && !fs.exists(archived)) {
- throw new CorruptedSnapshotException("Can't find hfile: " + hfile.getPath()
- + " in the real (" + realCfDir + ") or archive (" + archivedCfDir
- + ") directory for the primary table.", snapshot);
- }
+ // make sure we have all the expected store files
+ SnapshotReferenceUtil.visitRegionStoreFiles(fs, regionDir, new FSVisitor.StoreFileVisitor() {
+ public void storeFile(final String regionNameSuffix, final String family,
+ final String hfileName) throws IOException {
+ verifyStoreFile(snapshotDir, region, family, hfileName);
+ }
+ });
+ }
+
+ private void verifyStoreFile(final Path snapshotDir, final HRegionInfo regionInfo,
+ final String family, final String fileName) throws IOException {
+ Path refPath = null;
+ if (StoreFile.isReference(fileName)) {
+ // If is a reference file check if the parent file is present in the snapshot
+ Path snapshotHFilePath = new Path(new Path(
+ new Path(snapshotDir, regionInfo.getEncodedName()), family), fileName);
+ refPath = StoreFile.getReferredToFile(snapshotHFilePath);
+ if (!fs.exists(refPath)) {
+ throw new CorruptedSnapshotException("Missing parent hfile for: " + fileName, snapshot);
}
}
+
+ Path linkPath;
+ if (refPath != null && HFileLink.isHFileLink(refPath)) {
+ linkPath = new Path(family, refPath.getName());
+ } else if (HFileLink.isHFileLink(fileName)) {
+ linkPath = new Path(family, fileName);
+ } else {
+ linkPath = new Path(family, HFileLink.createHFileLinkName(tableName,
+ regionInfo.getEncodedName(), fileName));
+ }
+
+ // check if the linked file exists (in the archive, or in the table dir)
+ HFileLink link = new HFileLink(services.getConfiguration(), linkPath);
+ if (!link.exists(fs)) {
+ throw new CorruptedSnapshotException("Can't find hfile: " + fileName
+ + " in the real (" + link.getOriginPath() + ") or archive (" + link.getArchivePath()
+ + ") directory for the primary table.", snapshot);
+ }
}
/**
Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/RestoreSnapshotHandler.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/RestoreSnapshotHandler.java?rev=1515967&r1=1515966&r2=1515967&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/RestoreSnapshotHandler.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/RestoreSnapshotHandler.java Tue Aug 20 20:49:38 2013
@@ -125,6 +125,7 @@ public class RestoreSnapshotHandler exte
if (metaChanges.hasRegionsToRestore()) hris.addAll(metaChanges.getRegionsToRestore());
List<HRegionInfo> hrisToRemove = metaChanges.getRegionsToRemove();
MetaEditor.mutateRegions(catalogTracker, hrisToRemove, hris);
+ metaChanges.updateMetaParentRegions(catalogTracker, hris);
// At this point the restore is complete. Next step is enabling the table.
LOG.info("Restore snapshot=" + SnapshotDescriptionUtils.toString(snapshot) + " on table=" +
Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/TakeSnapshotHandler.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/TakeSnapshotHandler.java?rev=1515967&r1=1515966&r2=1515967&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/TakeSnapshotHandler.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/master/snapshot/TakeSnapshotHandler.java Tue Aug 20 20:49:38 2013
@@ -44,9 +44,13 @@ import org.apache.hadoop.hbase.master.me
import org.apache.hadoop.hbase.monitoring.MonitoredTask;
import org.apache.hadoop.hbase.monitoring.TaskMonitor;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
+import org.apache.hadoop.hbase.regionserver.HRegion;
+import org.apache.hadoop.hbase.snapshot.CopyRecoveredEditsTask;
+import org.apache.hadoop.hbase.snapshot.ReferenceRegionHFilesTask;
import org.apache.hadoop.hbase.snapshot.SnapshotCreationException;
import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
import org.apache.hadoop.hbase.snapshot.TableInfoCopyTask;
+import org.apache.hadoop.hbase.snapshot.TakeSnapshotUtils;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.zookeeper.KeeperException;
@@ -143,7 +147,7 @@ public abstract class TakeSnapshotHandle
List<Pair<HRegionInfo, ServerName>> regionsAndLocations =
MetaReader.getTableRegionsAndLocations(this.server.getCatalogTracker(),
- Bytes.toBytes(snapshot.getTable()), true);
+ Bytes.toBytes(snapshot.getTable()), false);
// run the snapshot
snapshotRegions(regionsAndLocations);
@@ -152,7 +156,11 @@ public abstract class TakeSnapshotHandle
// extract each pair to separate lists
Set<String> serverNames = new HashSet<String>();
for (Pair<HRegionInfo, ServerName> p : regionsAndLocations) {
- serverNames.add(p.getSecond().toString());
+ if (p != null && p.getFirst() != null && p.getSecond() != null) {
+ HRegionInfo hri = p.getFirst();
+ if (hri.isOffline() && (hri.isSplit() || hri.isSplitParent())) continue;
+ serverNames.add(p.getSecond().toString());
+ }
}
// verify the snapshot is valid
@@ -210,6 +218,32 @@ public abstract class TakeSnapshotHandle
}
/**
+ * Take a snapshot of the specified disabled region
+ */
+ protected void snapshotDisabledRegion(final HRegionInfo regionInfo)
+ throws IOException {
+ // 1 copy the regionInfo files to the snapshot
+ Path snapshotRegionDir = TakeSnapshotUtils.getRegionSnapshotDirectory(snapshot, rootDir,
+ regionInfo.getEncodedName());
+ HRegion.writeRegioninfoOnFilesystem(regionInfo, snapshotRegionDir, fs, conf);
+ // check for error for each region
+ monitor.rethrowException();
+
+ // 2 for each region, copy over its recovered.edits directory
+ Path regionDir = HRegion.getRegionDir(rootDir, regionInfo);
+ new CopyRecoveredEditsTask(snapshot, monitor, fs, regionDir, snapshotRegionDir).call();
+ monitor.rethrowException();
+ status.setStatus("Completed copying recovered edits for offline snapshot of table: "
+ + snapshot.getTable());
+
+ // 3 reference all the files in the region
+ new ReferenceRegionHFilesTask(snapshot, monitor, regionDir, fs, snapshotRegionDir).call();
+ monitor.rethrowException();
+ status.setStatus("Completed referencing HFiles for offline snapshot of table: " +
+ snapshot.getTable());
+ }
+
+ /**
* Snapshot the specified regions
*/
protected abstract void snapshotRegions(List<Pair<HRegionInfo, ServerName>> regions)
Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java?rev=1515967&r1=1515966&r2=1515967&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java Tue Aug 20 20:49:38 2013
@@ -2737,14 +2737,22 @@ public class HRegion implements HeapSize
if (exnSnare != null) {
exnSnare.rethrowException();
}
- Path file = storeFiles.get(i).getPath();
- // create "reference" to this store file. It is intentionally an empty file -- all
- // necessary infomration is captured by its fs location and filename. This allows us to
- // only figure out what needs to be done via a single nn operation (instead of having to
- // open and read the files as well).
+ StoreFile storeFile = storeFiles.get(i);
+ Path file = storeFile.getPath();
+
LOG.debug("Creating reference for file (" + (i+1) + "/" + sz + ") : " + file);
Path referenceFile = new Path(dstStoreDir, file.getName());
- boolean success = HBaseFileSystem.createNewFileOnFileSystem(fs, referenceFile);
+ boolean success = true;
+ if (storeFile.isReference()) {
+ // write the Reference object to the snapshot
+ storeFile.getReference().write(fs, referenceFile);
+ } else {
+ // create "reference" to this store file. It is intentionally an empty file -- all
+ // necessary information is captured by its fs location and filename. This allows us to
+ // only figure out what needs to be done via a single nn operation (instead of having to
+ // open and read the files as well).
+ success = HBaseFileSystem.createNewFileOnFileSystem(fs, referenceFile);
+ }
if (!success) {
throw new IOException("Failed to create reference file:" + referenceFile);
}
Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java?rev=1515967&r1=1515966&r2=1515967&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java Tue Aug 20 20:49:38 2013
@@ -322,6 +322,14 @@ public class StoreFile extends SchemaCon
}
/**
+ * @return the Reference object associated to this StoreFile.
+ * null if the StoreFile is not a reference.
+ */
+ Reference getReference() {
+ return this.reference;
+ }
+
+ /**
* @return <tt>true</tt> if this StoreFile is an HFileLink
*/
boolean isLink() {
Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/ExportSnapshot.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/ExportSnapshot.java?rev=1515967&r1=1515966&r2=1515967&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/ExportSnapshot.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/ExportSnapshot.java Tue Aug 20 20:49:38 2013
@@ -388,7 +388,7 @@ public final class ExportSnapshot extend
new SnapshotReferenceUtil.FileVisitor() {
public void storeFile (final String region, final String family, final String hfile)
throws IOException {
- Path path = new Path(family, HFileLink.createHFileLinkName(table, region, hfile));
+ Path path = HFileLink.createPath(table, region, family, hfile);
long size = new HFileLink(conf, path).getFileStatus(fs).getLen();
files.add(new Pair<Path, Long>(path, size));
}
@@ -627,7 +627,7 @@ public final class ExportSnapshot extend
if (outputFs.exists(snapshotTmpDir)) {
System.err.println("A snapshot with the same name '" + snapshotName + "' may be in-progress");
System.err.println("Please check " + snapshotTmpDir + ". If the snapshot has completed, ");
- System.err.println("consider removing " + snapshotTmpDir + " before retrying export");
+ System.err.println("consider removing " + snapshotTmpDir + " before retrying export");
return 1;
}
Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/RestoreSnapshotHelper.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/RestoreSnapshotHelper.java?rev=1515967&r1=1515966&r2=1515967&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/RestoreSnapshotHelper.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/RestoreSnapshotHelper.java Tue Aug 20 20:49:38 2013
@@ -41,6 +41,8 @@ import org.apache.hadoop.hbase.HColumnDe
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.backup.HFileArchiver;
+import org.apache.hadoop.hbase.catalog.CatalogTracker;
+import org.apache.hadoop.hbase.catalog.MetaEditor;
import org.apache.hadoop.hbase.monitoring.MonitoredTask;
import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher;
import org.apache.hadoop.hbase.io.HFileLink;
@@ -52,6 +54,7 @@ import org.apache.hadoop.hbase.util.Byte
import org.apache.hadoop.hbase.util.FSUtils;
import org.apache.hadoop.hbase.util.FSVisitor;
import org.apache.hadoop.hbase.util.ModifyRegionUtils;
+import org.apache.hadoop.hbase.util.Pair;
import org.apache.hadoop.io.IOUtils;
/**
@@ -102,6 +105,9 @@ public class RestoreSnapshotHelper {
private final Map<byte[], byte[]> regionsMap =
new TreeMap<byte[], byte[]>(Bytes.BYTES_COMPARATOR);
+ private final Map<String, Pair<String, String> > parentsMap =
+ new HashMap<String, Pair<String, String> >();
+
private final ForeignExceptionDispatcher monitor;
private final MonitoredTask status;
@@ -141,7 +147,7 @@ public class RestoreSnapshotHelper {
return null;
}
- RestoreMetaChanges metaChanges = new RestoreMetaChanges();
+ RestoreMetaChanges metaChanges = new RestoreMetaChanges(parentsMap);
// Identify which region are still available and which not.
// NOTE: we rely upon the region name as: "table name, start key, end key"
@@ -205,10 +211,16 @@ public class RestoreSnapshotHelper {
* Describe the set of operations needed to update META after restore.
*/
public static class RestoreMetaChanges {
+ private final Map<String, Pair<String, String> > parentsMap;
+
private List<HRegionInfo> regionsToRestore = null;
private List<HRegionInfo> regionsToRemove = null;
private List<HRegionInfo> regionsToAdd = null;
+ RestoreMetaChanges(final Map<String, Pair<String, String> > parentsMap) {
+ this.parentsMap = parentsMap;
+ }
+
/**
* @return true if there're new regions
*/
@@ -280,6 +292,50 @@ public class RestoreSnapshotHelper {
}
regionsToRestore.add(hri);
}
+
+ public void updateMetaParentRegions(final CatalogTracker catalogTracker,
+ final List<HRegionInfo> regionInfos) throws IOException {
+ if (regionInfos == null || parentsMap.isEmpty()) return;
+
+ // Extract region names and offlined regions
+ Map<String, HRegionInfo> regionsByName = new HashMap<String, HRegionInfo>(regionInfos.size());
+ List<HRegionInfo> parentRegions = new LinkedList();
+ for (HRegionInfo regionInfo: regionInfos) {
+ if (regionInfo.isSplitParent()) {
+ parentRegions.add(regionInfo);
+ } else {
+ regionsByName.put(regionInfo.getEncodedName(), regionInfo);
+ }
+ }
+
+ // Update Offline parents
+ for (HRegionInfo regionInfo: parentRegions) {
+ Pair<String, String> daughters = parentsMap.get(regionInfo.getEncodedName());
+
+ // TODO-REMOVE-ME: HConnectionManager.isTableAvailable() is checking the SERVER_QUALIFIER
+ // also on offline regions, so to keep the compatibility with older clients we must add
+ // a location to this region even if it will never be assigned. (See HBASE-9233)
+ MetaEditor.updateRegionLocation(catalogTracker, regionInfo,
+ catalogTracker.getMetaLocation());
+
+ if (daughters == null) {
+ // The snapshot contains an unreferenced region.
+ // It will be removed by the CatalogJanitor.
+ LOG.warn("Skip update of unreferenced offline parent: " + regionInfo);
+ continue;
+ }
+
+ // One side of the split is already compacted
+ if (daughters.getSecond() == null) {
+ daughters.setSecond(daughters.getFirst());
+ }
+
+ LOG.debug("Update splits parent " + regionInfo.getEncodedName() + " -> " + daughters);
+ MetaEditor.offlineParentInMeta(catalogTracker, regionInfo,
+ regionsByName.get(daughters.getFirst()),
+ regionsByName.get(daughters.getSecond()));
+ }
+ }
}
/**
@@ -492,9 +548,10 @@ public class RestoreSnapshotHelper {
private void restoreReferenceFile(final Path familyDir, final HRegionInfo regionInfo,
final String hfileName) throws IOException {
// Extract the referred information (hfile name and parent region)
- String tableName = snapshotDesc.getTable();
- Path refPath = StoreFile.getReferredToFile(new Path(new Path(new Path(tableName,
- regionInfo.getEncodedName()), familyDir.getName()), hfileName));
+ String snapshotTable = snapshotDesc.getTable();
+ Path refPath = StoreFile.getReferredToFile(new Path(new Path(new Path(
+ snapshotTable, regionInfo.getEncodedName()), familyDir.getName()),
+ hfileName));
String snapshotRegionName = refPath.getParent().getParent().getName();
String fileName = refPath.getName();
@@ -503,18 +560,40 @@ public class RestoreSnapshotHelper {
if (clonedRegionName == null) clonedRegionName = snapshotRegionName;
// The output file should be a reference link table=snapshotRegion-fileName.clonedRegionName
+ Path linkPath = null;
String refLink = fileName;
if (!HFileLink.isHFileLink(fileName)) {
- refLink = HFileLink.createHFileLinkName(tableName, snapshotRegionName, fileName);
+ refLink = HFileLink.createHFileLinkName(snapshotTable, snapshotRegionName, fileName);
+ linkPath = new Path(familyDir,
+ HFileLink.createHFileLinkName(snapshotTable, regionInfo.getEncodedName(), hfileName));
}
+
Path outPath = new Path(familyDir, refLink + '.' + clonedRegionName);
// Create the new reference
- Path linkPath = new Path(familyDir,
- HFileLink.createHFileLinkName(tableName, regionInfo.getEncodedName(), hfileName));
- InputStream in = new HFileLink(conf, linkPath).open(fs);
+ InputStream in;
+ if (linkPath != null) {
+ in = new HFileLink(conf, linkPath).open(fs);
+ } else {
+ linkPath = new Path(new Path(HRegion.getRegionDir(snapshotDir, regionInfo.getEncodedName()),
+ familyDir.getName()), hfileName);
+ in = fs.open(linkPath);
+ }
OutputStream out = fs.create(outPath);
IOUtils.copyBytes(in, out, conf);
+
+ // Add the daughter region to the map
+ String regionName = Bytes.toString(regionsMap.get(regionInfo.getEncodedNameAsBytes()));
+ LOG.debug("Restore reference " + regionName + " to " + clonedRegionName);
+ synchronized (parentsMap) {
+ Pair<String, String> daughters = parentsMap.get(clonedRegionName);
+ if (daughters == null) {
+ daughters = new Pair<String, String>(regionName, null);
+ parentsMap.put(clonedRegionName, daughters);
+ } else if (!regionName.equals(daughters.getFirst())) {
+ daughters.setSecond(regionName);
+ }
+ }
}
/**
@@ -526,9 +605,11 @@ public class RestoreSnapshotHelper {
* @return the new HRegion instance
*/
public HRegionInfo cloneRegionInfo(final HRegionInfo snapshotRegionInfo) {
- return new HRegionInfo(tableDesc.getName(),
+ HRegionInfo regionInfo = new HRegionInfo(tableDesc.getName(),
snapshotRegionInfo.getStartKey(), snapshotRegionInfo.getEndKey(),
snapshotRegionInfo.isSplit(), snapshotRegionInfo.getRegionId());
+ regionInfo.setOffline(snapshotRegionInfo.isOffline());
+ return regionInfo;
}
/**
Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotInfo.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotInfo.java?rev=1515967&r1=1515966&r2=1515967&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotInfo.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotInfo.java Tue Aug 20 20:49:38 2013
@@ -188,8 +188,7 @@ public final class SnapshotInfo extends
FileInfo addStoreFile(final String region, final String family, final String hfile)
throws IOException {
String table = this.snapshot.getTable();
- Path path = new Path(family, HFileLink.createHFileLinkName(table, region, hfile));
- HFileLink link = new HFileLink(conf, path);
+ HFileLink link = HFileLink.create(conf, table, region, family, hfile);
boolean inArchive = false;
long size = -1;
try {