HBASE-7777. HBCK check for lingering split parents should check for child regions
git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1444311 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e3b688719c
commit
b947807291
|
@ -241,7 +241,7 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
* When initially looking at HDFS, we attempt to find any orphaned data.
|
* When initially looking at HDFS, we attempt to find any orphaned data.
|
||||||
*/
|
*/
|
||||||
private List<HbckInfo> orphanHdfsDirs = Collections.synchronizedList(new ArrayList<HbckInfo>());
|
private List<HbckInfo> orphanHdfsDirs = Collections.synchronizedList(new ArrayList<HbckInfo>());
|
||||||
|
|
||||||
private Map<String, Set<String>> orphanTableDirs = new HashMap<String, Set<String>>();
|
private Map<String, Set<String>> orphanTableDirs = new HashMap<String, Set<String>>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -400,7 +400,7 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
if (!checkMetaOnly) {
|
if (!checkMetaOnly) {
|
||||||
reportTablesInFlux();
|
reportTablesInFlux();
|
||||||
}
|
}
|
||||||
|
|
||||||
// get regions according to what is online on each RegionServer
|
// get regions according to what is online on each RegionServer
|
||||||
loadDeployedRegions();
|
loadDeployedRegions();
|
||||||
|
|
||||||
|
@ -798,19 +798,21 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
if (!orphanTableDirs.containsKey(tableName)) {
|
if (!orphanTableDirs.containsKey(tableName)) {
|
||||||
LOG.warn("Unable to read .tableinfo from " + hbaseRoot, ioe);
|
LOG.warn("Unable to read .tableinfo from " + hbaseRoot, ioe);
|
||||||
//should only report once for each table
|
//should only report once for each table
|
||||||
errors.reportError(ERROR_CODE.NO_TABLEINFO_FILE,
|
errors.reportError(ERROR_CODE.NO_TABLEINFO_FILE,
|
||||||
"Unable to read .tableinfo from " + hbaseRoot + "/" + tableName);
|
"Unable to read .tableinfo from " + hbaseRoot + "/" + tableName);
|
||||||
Set<String> columns = new HashSet<String>();
|
Set<String> columns = new HashSet<String>();
|
||||||
orphanTableDirs.put(tableName, getColumnFamilyList(columns, hbi));
|
orphanTableDirs.put(tableName, getColumnFamilyList(columns, hbi));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
modTInfo.addRegionInfo(hbi);
|
if (!hbi.isSkipChecks()) {
|
||||||
|
modTInfo.addRegionInfo(hbi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tablesInfo;
|
return tablesInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To get the column family list according to the column family dirs
|
* To get the column family list according to the column family dirs
|
||||||
* @param columns
|
* @param columns
|
||||||
|
@ -828,7 +830,7 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
}
|
}
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To fabricate a .tableinfo file with following contents<br>
|
* To fabricate a .tableinfo file with following contents<br>
|
||||||
* 1. the correct tablename <br>
|
* 1. the correct tablename <br>
|
||||||
|
@ -846,7 +848,7 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
FSTableDescriptors.createTableDescriptor(htd, getConf(), true);
|
FSTableDescriptors.createTableDescriptor(htd, getConf(), true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To fix orphan table by creating a .tableinfo file under tableDir <br>
|
* To fix orphan table by creating a .tableinfo file under tableDir <br>
|
||||||
* 1. if TableInfo is cached, to recover the .tableinfo accordingly <br>
|
* 1. if TableInfo is cached, to recover the .tableinfo accordingly <br>
|
||||||
|
@ -1653,6 +1655,18 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
|
|
||||||
// ========== Cases where the region is in META =============
|
// ========== Cases where the region is in META =============
|
||||||
} else if (inMeta && inHdfs && !isDeployed && splitParent) {
|
} else if (inMeta && inHdfs && !isDeployed && splitParent) {
|
||||||
|
// check whether this is an actual error, or just transient state where parent
|
||||||
|
// is not cleaned
|
||||||
|
if (hbi.metaEntry.splitA != null && hbi.metaEntry.splitB != null) {
|
||||||
|
// check that split daughters are there
|
||||||
|
HbckInfo infoA = this.regionInfoMap.get(hbi.metaEntry.splitA.getEncodedName());
|
||||||
|
HbckInfo infoB = this.regionInfoMap.get(hbi.metaEntry.splitB.getEncodedName());
|
||||||
|
if (infoA != null && infoB != null) {
|
||||||
|
// we already processed or will process daughters. Move on, nothing to see here.
|
||||||
|
hbi.setSkipChecks(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
errors.reportError(ERROR_CODE.LINGERING_SPLIT_PARENT, "Region "
|
errors.reportError(ERROR_CODE.LINGERING_SPLIT_PARENT, "Region "
|
||||||
+ descriptiveName + " is a split parent in META, in HDFS, "
|
+ descriptiveName + " is a split parent in META, in HDFS, "
|
||||||
+ "and not deployed on any region server. This could be transient.");
|
+ "and not deployed on any region server. This could be transient.");
|
||||||
|
@ -1783,7 +1797,9 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
modTInfo.addServer(server);
|
modTInfo.addServer(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
modTInfo.addRegionInfo(hbi);
|
if (!hbi.isSkipChecks()) {
|
||||||
|
modTInfo.addRegionInfo(hbi);
|
||||||
|
}
|
||||||
|
|
||||||
tablesInfo.put(tableName, modTInfo);
|
tablesInfo.put(tableName, modTInfo);
|
||||||
}
|
}
|
||||||
|
@ -2547,7 +2563,8 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
|| hri.isMetaRegion() || hri.isRootRegion())) {
|
|| hri.isMetaRegion() || hri.isRootRegion())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
MetaEntry m = new MetaEntry(hri, sn, ts);
|
PairOfSameType<HRegionInfo> daughters = HRegionInfo.getDaughterRegions(result);
|
||||||
|
MetaEntry m = new MetaEntry(hri, sn, ts, daughters.getFirst(), daughters.getSecond());
|
||||||
HbckInfo hbInfo = new HbckInfo(m);
|
HbckInfo hbInfo = new HbckInfo(m);
|
||||||
HbckInfo previous = regionInfoMap.put(hri.getEncodedName(), hbInfo);
|
HbckInfo previous = regionInfoMap.put(hri.getEncodedName(), hbInfo);
|
||||||
if (previous != null) {
|
if (previous != null) {
|
||||||
|
@ -2586,11 +2603,19 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
static class MetaEntry extends HRegionInfo {
|
static class MetaEntry extends HRegionInfo {
|
||||||
ServerName regionServer; // server hosting this region
|
ServerName regionServer; // server hosting this region
|
||||||
long modTime; // timestamp of most recent modification metadata
|
long modTime; // timestamp of most recent modification metadata
|
||||||
|
HRegionInfo splitA, splitB; //split daughters
|
||||||
|
|
||||||
public MetaEntry(HRegionInfo rinfo, ServerName regionServer, long modTime) {
|
public MetaEntry(HRegionInfo rinfo, ServerName regionServer, long modTime) {
|
||||||
|
this(rinfo, regionServer, modTime, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetaEntry(HRegionInfo rinfo, ServerName regionServer, long modTime,
|
||||||
|
HRegionInfo splitA, HRegionInfo splitB) {
|
||||||
super(rinfo);
|
super(rinfo);
|
||||||
this.regionServer = regionServer;
|
this.regionServer = regionServer;
|
||||||
this.modTime = modTime;
|
this.modTime = modTime;
|
||||||
|
this.splitA = splitA;
|
||||||
|
this.splitB = splitB;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
|
@ -2639,6 +2664,7 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
private HdfsEntry hdfsEntry = null; // info in HDFS
|
private HdfsEntry hdfsEntry = null; // info in HDFS
|
||||||
private List<OnlineEntry> deployedEntries = Lists.newArrayList(); // on Region Server
|
private List<OnlineEntry> deployedEntries = Lists.newArrayList(); // on Region Server
|
||||||
private List<ServerName> deployedOn = Lists.newArrayList(); // info on RS's
|
private List<ServerName> deployedOn = Lists.newArrayList(); // info on RS's
|
||||||
|
private boolean skipChecks = false; // whether to skip further checks to this region info.
|
||||||
|
|
||||||
HbckInfo(MetaEntry metaEntry) {
|
HbckInfo(MetaEntry metaEntry) {
|
||||||
this.metaEntry = metaEntry;
|
this.metaEntry = metaEntry;
|
||||||
|
@ -2756,6 +2782,14 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
}
|
}
|
||||||
return hdfsEntry.hri;
|
return hdfsEntry.hri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSkipChecks(boolean skipChecks) {
|
||||||
|
this.skipChecks = skipChecks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSkipChecks() {
|
||||||
|
return skipChecks;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final static Comparator<HbckInfo> cmp = new Comparator<HbckInfo>() {
|
final static Comparator<HbckInfo> cmp = new Comparator<HbckInfo>() {
|
||||||
|
@ -3232,15 +3266,15 @@ public class HBaseFsck extends Configured implements Tool {
|
||||||
boolean shouldFixHdfsHoles() {
|
boolean shouldFixHdfsHoles() {
|
||||||
return fixHdfsHoles;
|
return fixHdfsHoles;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFixTableOrphans(boolean shouldFix) {
|
public void setFixTableOrphans(boolean shouldFix) {
|
||||||
fixTableOrphans = shouldFix;
|
fixTableOrphans = shouldFix;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean shouldFixTableOrphans() {
|
boolean shouldFixTableOrphans() {
|
||||||
return fixTableOrphans;
|
return fixTableOrphans;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFixHdfsOverlaps(boolean shouldFix) {
|
public void setFixHdfsOverlaps(boolean shouldFix) {
|
||||||
fixHdfsOverlaps = shouldFix;
|
fixHdfsOverlaps = shouldFix;
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,7 +207,6 @@ public class TestEndToEndSplitTransaction {
|
||||||
HTable table;
|
HTable table;
|
||||||
byte[] tableName, family;
|
byte[] tableName, family;
|
||||||
HBaseAdmin admin;
|
HBaseAdmin admin;
|
||||||
HTable metaTable;
|
|
||||||
HRegionServer rs;
|
HRegionServer rs;
|
||||||
|
|
||||||
RegionSplitter(HTable table) throws IOException {
|
RegionSplitter(HTable table) throws IOException {
|
||||||
|
@ -216,7 +215,6 @@ public class TestEndToEndSplitTransaction {
|
||||||
this.family = table.getTableDescriptor().getFamiliesKeys().iterator().next();
|
this.family = table.getTableDescriptor().getFamiliesKeys().iterator().next();
|
||||||
admin = TEST_UTIL.getHBaseAdmin();
|
admin = TEST_UTIL.getHBaseAdmin();
|
||||||
rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0);
|
rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0);
|
||||||
metaTable = new HTable(conf, HConstants.META_TABLE_NAME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -247,14 +245,14 @@ public class TestEndToEndSplitTransaction {
|
||||||
addData(start);
|
addData(start);
|
||||||
addData(mid);
|
addData(mid);
|
||||||
|
|
||||||
flushAndBlockUntilDone(region.getRegionName());
|
flushAndBlockUntilDone(admin, rs, region.getRegionName());
|
||||||
compactAndBlockUntilDone(region.getRegionName());
|
compactAndBlockUntilDone(admin, rs, region.getRegionName());
|
||||||
|
|
||||||
log("Initiating region split for:" + region.getRegionNameAsString());
|
log("Initiating region split for:" + region.getRegionNameAsString());
|
||||||
try {
|
try {
|
||||||
admin.split(region.getRegionName(), splitPoint);
|
admin.split(region.getRegionName(), splitPoint);
|
||||||
//wait until the split is complete
|
//wait until the split is complete
|
||||||
blockUntilRegionSplit(50000, region.getRegionName(), true);
|
blockUntilRegionSplit(conf, 50000, region.getRegionName(), true);
|
||||||
|
|
||||||
} catch (NotServingRegionException ex) {
|
} catch (NotServingRegionException ex) {
|
||||||
//ignore
|
//ignore
|
||||||
|
@ -262,10 +260,6 @@ public class TestEndToEndSplitTransaction {
|
||||||
}
|
}
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
this.ex = ex;
|
this.ex = ex;
|
||||||
} finally {
|
|
||||||
if (metaTable != null) {
|
|
||||||
IOUtils.closeQuietly(metaTable);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,106 +272,6 @@ public class TestEndToEndSplitTransaction {
|
||||||
}
|
}
|
||||||
table.flushCommits();
|
table.flushCommits();
|
||||||
}
|
}
|
||||||
|
|
||||||
void flushAndBlockUntilDone(byte[] regionName) throws IOException, InterruptedException {
|
|
||||||
log("flushing region: " + Bytes.toStringBinary(regionName));
|
|
||||||
admin.flush(regionName);
|
|
||||||
log("blocking until flush is complete: " + Bytes.toStringBinary(regionName));
|
|
||||||
Threads.sleepWithoutInterrupt(500);
|
|
||||||
while (rs.cacheFlusher.getFlushQueueSize() > 0) {
|
|
||||||
Threads.sleep(50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void compactAndBlockUntilDone(byte[] regionName) throws IOException,
|
|
||||||
InterruptedException {
|
|
||||||
log("Compacting region: " + Bytes.toStringBinary(regionName));
|
|
||||||
admin.majorCompact(regionName);
|
|
||||||
log("blocking until compaction is complete: " + Bytes.toStringBinary(regionName));
|
|
||||||
Threads.sleepWithoutInterrupt(500);
|
|
||||||
while (rs.compactSplitThread.getCompactionQueueSize() > 0) {
|
|
||||||
Threads.sleep(50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** bloks until the region split is complete in META and region server opens the daughters */
|
|
||||||
void blockUntilRegionSplit(long timeout, final byte[] regionName, boolean waitForDaughters)
|
|
||||||
throws IOException, InterruptedException {
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
log("blocking until region is split:" + Bytes.toStringBinary(regionName));
|
|
||||||
HRegionInfo daughterA = null, daughterB = null;
|
|
||||||
|
|
||||||
while (System.currentTimeMillis() - start < timeout) {
|
|
||||||
Result result = getRegionRow(regionName);
|
|
||||||
if (result == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRegionInfo region = HRegionInfo.getHRegionInfo(result);
|
|
||||||
if(region.isSplitParent()) {
|
|
||||||
log("found parent region: " + region.toString());
|
|
||||||
PairOfSameType<HRegionInfo> pair = HRegionInfo.getDaughterRegions(result);
|
|
||||||
daughterA = pair.getFirst();
|
|
||||||
daughterB = pair.getSecond();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sleep(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
//if we are here, this means the region split is complete or timed out
|
|
||||||
if (waitForDaughters) {
|
|
||||||
long rem = timeout - (System.currentTimeMillis() - start);
|
|
||||||
blockUntilRegionIsInMeta(rem, daughterA.getRegionName());
|
|
||||||
|
|
||||||
rem = timeout - (System.currentTimeMillis() - start);
|
|
||||||
blockUntilRegionIsInMeta(rem, daughterB.getRegionName());
|
|
||||||
|
|
||||||
rem = timeout - (System.currentTimeMillis() - start);
|
|
||||||
blockUntilRegionIsOpenedByRS(rem, daughterA.getRegionName());
|
|
||||||
|
|
||||||
rem = timeout - (System.currentTimeMillis() - start);
|
|
||||||
blockUntilRegionIsOpenedByRS(rem, daughterB.getRegionName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result getRegionRow(byte[] regionName) throws IOException {
|
|
||||||
Get get = new Get(regionName);
|
|
||||||
return metaTable.get(get);
|
|
||||||
}
|
|
||||||
|
|
||||||
void blockUntilRegionIsInMeta(long timeout, byte[] regionName)
|
|
||||||
throws IOException, InterruptedException {
|
|
||||||
log("blocking until region is in META: " + Bytes.toStringBinary(regionName));
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
while (System.currentTimeMillis() - start < timeout) {
|
|
||||||
Result result = getRegionRow(regionName);
|
|
||||||
if (result != null) {
|
|
||||||
HRegionInfo info = HRegionInfo.getHRegionInfo(result);
|
|
||||||
if (info != null && !info.isOffline()) {
|
|
||||||
log("found region in META: " + Bytes.toStringBinary(regionName));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sleep(10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void blockUntilRegionIsOpenedByRS(long timeout, byte[] regionName)
|
|
||||||
throws IOException, InterruptedException {
|
|
||||||
log("blocking until region is opened by region server: " + Bytes.toStringBinary(regionName));
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
while (System.currentTimeMillis() - start < timeout) {
|
|
||||||
List<HRegion> regions = rs.getOnlineRegions(tableName);
|
|
||||||
for (HRegion region : regions) {
|
|
||||||
if (Bytes.compareTo(region.getRegionName(), regionName) == 0) {
|
|
||||||
log("found region open in RS: " + Bytes.toStringBinary(regionName));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sleep(10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -484,5 +378,118 @@ public class TestEndToEndSplitTransaction {
|
||||||
LOG.info(msg);
|
LOG.info(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* some utility methods for split tests */
|
||||||
|
|
||||||
|
public static void flushAndBlockUntilDone(HBaseAdmin admin, HRegionServer rs, byte[] regionName)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
log("flushing region: " + Bytes.toStringBinary(regionName));
|
||||||
|
admin.flush(regionName);
|
||||||
|
log("blocking until flush is complete: " + Bytes.toStringBinary(regionName));
|
||||||
|
Threads.sleepWithoutInterrupt(500);
|
||||||
|
while (rs.cacheFlusher.getFlushQueueSize() > 0) {
|
||||||
|
Threads.sleep(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void compactAndBlockUntilDone(HBaseAdmin admin, HRegionServer rs, byte[] regionName)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
log("Compacting region: " + Bytes.toStringBinary(regionName));
|
||||||
|
admin.majorCompact(regionName);
|
||||||
|
log("blocking until compaction is complete: " + Bytes.toStringBinary(regionName));
|
||||||
|
Threads.sleepWithoutInterrupt(500);
|
||||||
|
while (rs.compactSplitThread.getCompactionQueueSize() > 0) {
|
||||||
|
Threads.sleep(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Blocks until the region split is complete in META and region server opens the daughters */
|
||||||
|
public static void blockUntilRegionSplit(Configuration conf, long timeout,
|
||||||
|
final byte[] regionName, boolean waitForDaughters)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
log("blocking until region is split:" + Bytes.toStringBinary(regionName));
|
||||||
|
HRegionInfo daughterA = null, daughterB = null;
|
||||||
|
HTable metaTable = new HTable(conf, HConstants.META_TABLE_NAME);
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (System.currentTimeMillis() - start < timeout) {
|
||||||
|
Result result = getRegionRow(metaTable, regionName);
|
||||||
|
if (result == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRegionInfo region = HRegionInfo.getHRegionInfo(result);
|
||||||
|
if(region.isSplitParent()) {
|
||||||
|
log("found parent region: " + region.toString());
|
||||||
|
PairOfSameType<HRegionInfo> pair = HRegionInfo.getDaughterRegions(result);
|
||||||
|
daughterA = pair.getFirst();
|
||||||
|
daughterB = pair.getSecond();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Threads.sleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
//if we are here, this means the region split is complete or timed out
|
||||||
|
if (waitForDaughters) {
|
||||||
|
long rem = timeout - (System.currentTimeMillis() - start);
|
||||||
|
blockUntilRegionIsInMeta(metaTable, rem, daughterA);
|
||||||
|
|
||||||
|
rem = timeout - (System.currentTimeMillis() - start);
|
||||||
|
blockUntilRegionIsInMeta(metaTable, rem, daughterB);
|
||||||
|
|
||||||
|
rem = timeout - (System.currentTimeMillis() - start);
|
||||||
|
blockUntilRegionIsOpened(conf, rem, daughterA);
|
||||||
|
|
||||||
|
rem = timeout - (System.currentTimeMillis() - start);
|
||||||
|
blockUntilRegionIsOpened(conf, rem, daughterB);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(metaTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result getRegionRow(HTable metaTable, byte[] regionName) throws IOException {
|
||||||
|
Get get = new Get(regionName);
|
||||||
|
return metaTable.get(get);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void blockUntilRegionIsInMeta(HTable metaTable, long timeout, HRegionInfo hri)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
log("blocking until region is in META: " + hri.getRegionNameAsString());
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
while (System.currentTimeMillis() - start < timeout) {
|
||||||
|
Result result = getRegionRow(metaTable, hri.getRegionName());
|
||||||
|
if (result != null) {
|
||||||
|
HRegionInfo info = HRegionInfo.getHRegionInfo(result);
|
||||||
|
if (info != null && !info.isOffline()) {
|
||||||
|
log("found region in META: " + hri.getRegionNameAsString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Threads.sleep(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void blockUntilRegionIsOpened(Configuration conf, long timeout, HRegionInfo hri)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
log("blocking until region is opened for reading:" + hri.getRegionNameAsString());
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
HTable table = new HTable(conf, hri.getTableName());
|
||||||
|
|
||||||
|
try {
|
||||||
|
Get get = new Get(hri.getStartKey());
|
||||||
|
while (System.currentTimeMillis() - start < timeout) {
|
||||||
|
try {
|
||||||
|
table.get(get);
|
||||||
|
break;
|
||||||
|
} catch(IOException ex) {
|
||||||
|
//wait some more
|
||||||
|
}
|
||||||
|
Threads.sleep(10);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ import java.util.Map.Entry;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
@ -71,11 +72,12 @@ import org.apache.hadoop.hbase.master.RegionStates;
|
||||||
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
|
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
|
||||||
import org.apache.hadoop.hbase.regionserver.HRegion;
|
import org.apache.hadoop.hbase.regionserver.HRegion;
|
||||||
import org.apache.hadoop.hbase.regionserver.HRegionServer;
|
import org.apache.hadoop.hbase.regionserver.HRegionServer;
|
||||||
|
import org.apache.hadoop.hbase.regionserver.TestEndToEndSplitTransaction;
|
||||||
import org.apache.hadoop.hbase.util.HBaseFsck.ErrorReporter;
|
import org.apache.hadoop.hbase.util.HBaseFsck.ErrorReporter;
|
||||||
import org.apache.hadoop.hbase.util.HBaseFsck.PrintingErrorReporter;
|
|
||||||
import org.apache.hadoop.hbase.util.HBaseFsck.TableInfo;
|
|
||||||
import org.apache.hadoop.hbase.util.HBaseFsck.ErrorReporter.ERROR_CODE;
|
import org.apache.hadoop.hbase.util.HBaseFsck.ErrorReporter.ERROR_CODE;
|
||||||
import org.apache.hadoop.hbase.util.HBaseFsck.HbckInfo;
|
import org.apache.hadoop.hbase.util.HBaseFsck.HbckInfo;
|
||||||
|
import org.apache.hadoop.hbase.util.HBaseFsck.PrintingErrorReporter;
|
||||||
|
import org.apache.hadoop.hbase.util.HBaseFsck.TableInfo;
|
||||||
import org.apache.hadoop.hbase.util.hbck.HFileCorruptionChecker;
|
import org.apache.hadoop.hbase.util.hbck.HFileCorruptionChecker;
|
||||||
import org.apache.hadoop.hbase.util.hbck.HbckTestingUtil;
|
import org.apache.hadoop.hbase.util.hbck.HbckTestingUtil;
|
||||||
import org.apache.hadoop.hbase.zookeeper.ZKAssign;
|
import org.apache.hadoop.hbase.zookeeper.ZKAssign;
|
||||||
|
@ -402,7 +404,7 @@ public class TestHBaseFsck {
|
||||||
deleteTable(table);
|
deleteTable(table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHbckFixOrphanTable() throws Exception {
|
public void testHbckFixOrphanTable() throws Exception {
|
||||||
String table = "tableInfo";
|
String table = "tableInfo";
|
||||||
|
@ -411,31 +413,31 @@ public class TestHBaseFsck {
|
||||||
try {
|
try {
|
||||||
setupTable(table);
|
setupTable(table);
|
||||||
HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
|
HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
|
||||||
|
|
||||||
Path hbaseTableDir = new Path(conf.get(HConstants.HBASE_DIR) + "/" + table );
|
Path hbaseTableDir = new Path(conf.get(HConstants.HBASE_DIR) + "/" + table );
|
||||||
fs = hbaseTableDir.getFileSystem(conf);
|
fs = hbaseTableDir.getFileSystem(conf);
|
||||||
FileStatus status = FSTableDescriptors.getTableInfoPath(fs, hbaseTableDir);
|
FileStatus status = FSTableDescriptors.getTableInfoPath(fs, hbaseTableDir);
|
||||||
tableinfo = status.getPath();
|
tableinfo = status.getPath();
|
||||||
fs.rename(tableinfo, new Path("/.tableinfo"));
|
fs.rename(tableinfo, new Path("/.tableinfo"));
|
||||||
|
|
||||||
//to report error if .tableinfo is missing.
|
//to report error if .tableinfo is missing.
|
||||||
HBaseFsck hbck = doFsck(conf, false);
|
HBaseFsck hbck = doFsck(conf, false);
|
||||||
assertErrors(hbck, new ERROR_CODE[] { ERROR_CODE.NO_TABLEINFO_FILE });
|
assertErrors(hbck, new ERROR_CODE[] { ERROR_CODE.NO_TABLEINFO_FILE });
|
||||||
|
|
||||||
// fix OrphanTable with default .tableinfo (htd not yet cached on master)
|
// fix OrphanTable with default .tableinfo (htd not yet cached on master)
|
||||||
hbck = doFsck(conf, true);
|
hbck = doFsck(conf, true);
|
||||||
assertNoErrors(hbck);
|
assertNoErrors(hbck);
|
||||||
status = null;
|
status = null;
|
||||||
status = FSTableDescriptors.getTableInfoPath(fs, hbaseTableDir);
|
status = FSTableDescriptors.getTableInfoPath(fs, hbaseTableDir);
|
||||||
assertNotNull(status);
|
assertNotNull(status);
|
||||||
|
|
||||||
HTableDescriptor htd = admin.getTableDescriptor(table.getBytes());
|
HTableDescriptor htd = admin.getTableDescriptor(table.getBytes());
|
||||||
htd.setValue("NOT_DEFAULT", "true");
|
htd.setValue("NOT_DEFAULT", "true");
|
||||||
admin.disableTable(table);
|
admin.disableTable(table);
|
||||||
admin.modifyTable(table.getBytes(), htd);
|
admin.modifyTable(table.getBytes(), htd);
|
||||||
admin.enableTable(table);
|
admin.enableTable(table);
|
||||||
fs.delete(status.getPath(), true);
|
fs.delete(status.getPath(), true);
|
||||||
|
|
||||||
// fix OrphanTable with cache
|
// fix OrphanTable with cache
|
||||||
htd = admin.getTableDescriptor(table.getBytes()); // warms up cached htd on master
|
htd = admin.getTableDescriptor(table.getBytes()); // warms up cached htd on master
|
||||||
hbck = doFsck(conf, true);
|
hbck = doFsck(conf, true);
|
||||||
|
@ -1194,6 +1196,7 @@ public class TestHBaseFsck {
|
||||||
@Test
|
@Test
|
||||||
public void testLingeringSplitParent() throws Exception {
|
public void testLingeringSplitParent() throws Exception {
|
||||||
String table = "testLingeringSplitParent";
|
String table = "testLingeringSplitParent";
|
||||||
|
HTable meta = null;
|
||||||
try {
|
try {
|
||||||
setupTable(table);
|
setupTable(table);
|
||||||
assertEquals(ROWKEYS.length, countRows());
|
assertEquals(ROWKEYS.length, countRows());
|
||||||
|
@ -1207,7 +1210,7 @@ public class TestHBaseFsck {
|
||||||
Bytes.toBytes("C"), true, true, false);
|
Bytes.toBytes("C"), true, true, false);
|
||||||
|
|
||||||
// Create a new meta entry to fake it as a split parent.
|
// Create a new meta entry to fake it as a split parent.
|
||||||
HTable meta = new HTable(conf, HTableDescriptor.META_TABLEDESC.getName());
|
meta = new HTable(conf, HTableDescriptor.META_TABLEDESC.getName());
|
||||||
HRegionInfo hri = location.getRegionInfo();
|
HRegionInfo hri = location.getRegionInfo();
|
||||||
|
|
||||||
HRegionInfo a = new HRegionInfo(tbl.getTableName(),
|
HRegionInfo a = new HRegionInfo(tbl.getTableName(),
|
||||||
|
@ -1260,6 +1263,119 @@ public class TestHBaseFsck {
|
||||||
assertEquals(ROWKEYS.length, countRows());
|
assertEquals(ROWKEYS.length, countRows());
|
||||||
} finally {
|
} finally {
|
||||||
deleteTable(table);
|
deleteTable(table);
|
||||||
|
IOUtils.closeQuietly(meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that LINGERING_SPLIT_PARENT is not erroneously reported for
|
||||||
|
* valid cases where the daughters are there.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testValidLingeringSplitParent() throws Exception {
|
||||||
|
String table = "testLingeringSplitParent";
|
||||||
|
HTable meta = null;
|
||||||
|
try {
|
||||||
|
setupTable(table);
|
||||||
|
assertEquals(ROWKEYS.length, countRows());
|
||||||
|
|
||||||
|
// make sure data in regions, if in hlog only there is no data loss
|
||||||
|
TEST_UTIL.getHBaseAdmin().flush(table);
|
||||||
|
HRegionLocation location = tbl.getRegionLocation("B");
|
||||||
|
|
||||||
|
meta = new HTable(conf, HTableDescriptor.META_TABLEDESC.getName());
|
||||||
|
HRegionInfo hri = location.getRegionInfo();
|
||||||
|
|
||||||
|
// do a regular split
|
||||||
|
HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
|
||||||
|
byte[] regionName = location.getRegionInfo().getRegionName();
|
||||||
|
admin.split(location.getRegionInfo().getRegionName(), Bytes.toBytes("BM"));
|
||||||
|
TestEndToEndSplitTransaction.blockUntilRegionSplit(
|
||||||
|
TEST_UTIL.getConfiguration(), 60000, regionName, true);
|
||||||
|
|
||||||
|
// TODO: fixHdfsHoles does not work against splits, since the parent dir lingers on
|
||||||
|
// for some time until children references are deleted. HBCK erroneously sees this as
|
||||||
|
// overlapping regions
|
||||||
|
HBaseFsck hbck = doFsck(conf, true, true, false, false, false, true, true, true, null);
|
||||||
|
assertErrors(hbck, new ERROR_CODE[] {}); //no LINGERING_SPLIT_PARENT reported
|
||||||
|
|
||||||
|
// assert that the split META entry is still there.
|
||||||
|
Get get = new Get(hri.getRegionName());
|
||||||
|
Result result = meta.get(get);
|
||||||
|
assertNotNull(result);
|
||||||
|
assertNotNull(HRegionInfo.getHRegionInfo(result));
|
||||||
|
|
||||||
|
assertEquals(ROWKEYS.length, countRows());
|
||||||
|
|
||||||
|
// assert that we still have the split regions
|
||||||
|
assertEquals(tbl.getStartKeys().length, SPLITS.length + 1 + 1); //SPLITS + 1 is # regions pre-split.
|
||||||
|
assertNoErrors(doFsck(conf, false));
|
||||||
|
} finally {
|
||||||
|
deleteTable(table);
|
||||||
|
IOUtils.closeQuietly(meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split crashed after write to META finished for the parent region, but
|
||||||
|
* failed to write daughters (pre HBASE-7721 codebase)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSplitDaughtersNotInMeta() throws Exception {
|
||||||
|
String table = "testSplitdaughtersNotInMeta";
|
||||||
|
HTable meta = null;
|
||||||
|
try {
|
||||||
|
setupTable(table);
|
||||||
|
assertEquals(ROWKEYS.length, countRows());
|
||||||
|
|
||||||
|
// make sure data in regions, if in hlog only there is no data loss
|
||||||
|
TEST_UTIL.getHBaseAdmin().flush(table);
|
||||||
|
HRegionLocation location = tbl.getRegionLocation("B");
|
||||||
|
|
||||||
|
meta = new HTable(conf, HTableDescriptor.META_TABLEDESC.getName());
|
||||||
|
HRegionInfo hri = location.getRegionInfo();
|
||||||
|
|
||||||
|
// do a regular split
|
||||||
|
HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
|
||||||
|
byte[] regionName = location.getRegionInfo().getRegionName();
|
||||||
|
admin.split(location.getRegionInfo().getRegionName(), Bytes.toBytes("BM"));
|
||||||
|
TestEndToEndSplitTransaction.blockUntilRegionSplit(
|
||||||
|
TEST_UTIL.getConfiguration(), 60000, regionName, true);
|
||||||
|
|
||||||
|
PairOfSameType<HRegionInfo> daughters = HRegionInfo.getDaughterRegions(meta.get(new Get(regionName)));
|
||||||
|
|
||||||
|
// Delete daughter regions from meta, but not hdfs, unassign it.
|
||||||
|
Map<HRegionInfo, ServerName> hris = tbl.getRegionLocations();
|
||||||
|
undeployRegion(admin, hris.get(daughters.getFirst()), daughters.getFirst());
|
||||||
|
undeployRegion(admin, hris.get(daughters.getSecond()), daughters.getSecond());
|
||||||
|
|
||||||
|
meta.delete(new Delete(daughters.getFirst().getRegionName()));
|
||||||
|
meta.delete(new Delete(daughters.getSecond().getRegionName()));
|
||||||
|
meta.flushCommits();
|
||||||
|
|
||||||
|
HBaseFsck hbck = doFsck(conf, false);
|
||||||
|
assertErrors(hbck, new ERROR_CODE[] {ERROR_CODE.NOT_IN_META_OR_DEPLOYED,
|
||||||
|
ERROR_CODE.NOT_IN_META_OR_DEPLOYED, ERROR_CODE.HOLE_IN_REGION_CHAIN}); //no LINGERING_SPLIT_PARENT
|
||||||
|
|
||||||
|
// now fix it. The fix should not revert the region split, but add daughters to META
|
||||||
|
hbck = doFsck(conf, true, true, false, false, false, false, false, false, null);
|
||||||
|
assertErrors(hbck, new ERROR_CODE[] {ERROR_CODE.NOT_IN_META_OR_DEPLOYED,
|
||||||
|
ERROR_CODE.NOT_IN_META_OR_DEPLOYED, ERROR_CODE.HOLE_IN_REGION_CHAIN});
|
||||||
|
|
||||||
|
// assert that the split META entry is still there.
|
||||||
|
Get get = new Get(hri.getRegionName());
|
||||||
|
Result result = meta.get(get);
|
||||||
|
assertNotNull(result);
|
||||||
|
assertNotNull(HRegionInfo.getHRegionInfo(result));
|
||||||
|
|
||||||
|
assertEquals(ROWKEYS.length, countRows());
|
||||||
|
|
||||||
|
// assert that we still have the split regions
|
||||||
|
assertEquals(tbl.getStartKeys().length, SPLITS.length + 1 + 1); //SPLITS + 1 is # regions pre-split.
|
||||||
|
assertNoErrors(doFsck(conf, false)); //should be fixed by now
|
||||||
|
} finally {
|
||||||
|
deleteTable(table);
|
||||||
|
IOUtils.closeQuietly(meta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue