HBASE-24247 Failed multi-merge because two regions not adjacent (legitimately) (#1570)
hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionInfo.java Add new isOverlap method that takes list of RegionInfos checking that current RegionInfo is overlapped by the passed in Regions. Signed-off-by: Jan Hentschel <jan.hentschel@ultratendency.com> Signed-off-by: Huaxiang Sun <huaxiangsun@apache.com>
This commit is contained in:
parent
8eb2f6752c
commit
9e697d0ea6
|
@ -796,6 +796,16 @@ public interface RegionInfo extends Comparable<RegionInfo> {
|
||||||
return !isLast() && Bytes.compareTo(getStartKey(), getEndKey()) > 0;
|
return !isLast() && Bytes.compareTo(getStartKey(), getEndKey()) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
default boolean isOverlap(RegionInfo [] ris) {
|
||||||
|
for (RegionInfo ri: ris) {
|
||||||
|
if (isOverlap(ri)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return True if an overlap in region range.
|
* @return True if an overlap in region range.
|
||||||
* @see #isDegenerate()
|
* @see #isDegenerate()
|
||||||
|
|
|
@ -133,7 +133,7 @@ public class MergeTableRegionsProcedure
|
||||||
LOG.warn(msg);
|
LOG.warn(msg);
|
||||||
throw new MergeRegionException(msg);
|
throw new MergeRegionException(msg);
|
||||||
}
|
}
|
||||||
if (!force && !ri.isAdjacent(previous) && !ri.isOverlap(previous)) {
|
if (!force && !ri.isAdjacent(previous) && !ri.isOverlap(regions)) {
|
||||||
String msg = "Unable to merge non-adjacent or non-overlapping regions " +
|
String msg = "Unable to merge non-adjacent or non-overlapping regions " +
|
||||||
previous.getShortNameToLog() + ", " + ri.getShortNameToLog() + " when force=false";
|
previous.getShortNameToLog() + ", " + ri.getShortNameToLog() + " when force=false";
|
||||||
LOG.warn(msg);
|
LOG.warn(msg);
|
||||||
|
@ -142,7 +142,7 @@ public class MergeTableRegionsProcedure
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ri.getReplicaId() != RegionInfo.DEFAULT_REPLICA_ID) {
|
if (ri.getReplicaId() != RegionInfo.DEFAULT_REPLICA_ID) {
|
||||||
throw new MergeRegionException("Can't merge non-default replicas; " + ri);
|
throw new MergeRegionException("Can't merge non-default/replicaId!=0 replicas; " + ri);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
checkOnline(env, ri);
|
checkOnline(env, ri);
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.apache.hadoop.hbase.MetaTableAccessor;
|
||||||
import org.apache.hadoop.hbase.TableName;
|
import org.apache.hadoop.hbase.TableName;
|
||||||
import org.apache.hadoop.hbase.client.RegionInfo;
|
import org.apache.hadoop.hbase.client.RegionInfo;
|
||||||
import org.apache.hadoop.hbase.client.RegionInfoBuilder;
|
import org.apache.hadoop.hbase.client.RegionInfoBuilder;
|
||||||
|
import org.apache.hadoop.hbase.master.assignment.GCRegionProcedure;
|
||||||
import org.apache.hadoop.hbase.testclassification.LargeTests;
|
import org.apache.hadoop.hbase.testclassification.LargeTests;
|
||||||
import org.apache.hadoop.hbase.testclassification.MasterTests;
|
import org.apache.hadoop.hbase.testclassification.MasterTests;
|
||||||
import org.apache.hadoop.hbase.util.Threads;
|
import org.apache.hadoop.hbase.util.Threads;
|
||||||
|
@ -175,6 +176,51 @@ public class TestMetaFixer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make it so a big overlap spans many Regions, some of which are non-contiguous. Make it so
|
||||||
|
* we can fix this condition. HBASE-24247
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testOverlapWithMergeOfNonContiguous() throws Exception {
|
||||||
|
TableName tn = TableName.valueOf(this.name.getMethodName());
|
||||||
|
TEST_UTIL.createMultiRegionTable(tn, HConstants.CATALOG_FAMILY);
|
||||||
|
List<RegionInfo> ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), tn);
|
||||||
|
assertTrue(ris.size() > 5);
|
||||||
|
MasterServices services = TEST_UTIL.getHBaseCluster().getMaster();
|
||||||
|
services.getCatalogJanitor().scan();
|
||||||
|
CatalogJanitor.Report report = services.getCatalogJanitor().getLastReport();
|
||||||
|
assertTrue(report.isEmpty());
|
||||||
|
// Make a simple overlap spanning second and third region.
|
||||||
|
makeOverlap(services, ris.get(1), ris.get(5));
|
||||||
|
// Now Delete a region under the overlap to manufacture non-contiguous sub regions.
|
||||||
|
RegionInfo deletedRegion = ris.get(3);
|
||||||
|
long pid = services.getAssignmentManager().unassign(deletedRegion);
|
||||||
|
while (!services.getMasterProcedureExecutor().isFinished(pid)) {
|
||||||
|
Threads.sleep(100);
|
||||||
|
}
|
||||||
|
GCRegionProcedure procedure =
|
||||||
|
new GCRegionProcedure(services.getMasterProcedureExecutor().getEnvironment(), ris.get(3));
|
||||||
|
pid = services.getMasterProcedureExecutor().submitProcedure(procedure);
|
||||||
|
while (!services.getMasterProcedureExecutor().isFinished(pid)) {
|
||||||
|
Threads.sleep(100);
|
||||||
|
}
|
||||||
|
Threads.sleep(10000);
|
||||||
|
services.getCatalogJanitor().scan();
|
||||||
|
report = services.getCatalogJanitor().getLastReport();
|
||||||
|
assertEquals(1, MetaFixer.calculateMerges(10, report.getOverlaps()).size());
|
||||||
|
MetaFixer fixer = new MetaFixer(services);
|
||||||
|
fixer.fixOverlaps(report);
|
||||||
|
await(10, () -> {
|
||||||
|
try {
|
||||||
|
services.getCatalogJanitor().scan();
|
||||||
|
final CatalogJanitor.Report postReport = services.getCatalogJanitor().getLastReport();
|
||||||
|
return postReport.isEmpty();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Await the successful return of {@code condition}, sleeping {@code sleepMillis} between
|
* Await the successful return of {@code condition}, sleeping {@code sleepMillis} between
|
||||||
* invocations.
|
* invocations.
|
||||||
|
|
|
@ -16,14 +16,12 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.hbase.regionserver;
|
package org.apache.hadoop.hbase.regionserver;
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotEquals;
|
import static org.junit.Assert.assertNotEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.FileStatus;
|
import org.apache.hadoop.fs.FileStatus;
|
||||||
|
@ -48,9 +46,7 @@ import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.experimental.categories.Category;
|
import org.junit.experimental.categories.Category;
|
||||||
import org.junit.rules.TestName;
|
import org.junit.rules.TestName;
|
||||||
|
|
||||||
import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations;
|
import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations;
|
||||||
|
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
|
||||||
|
|
||||||
@Category({RegionServerTests.class, SmallTests.class})
|
@Category({RegionServerTests.class, SmallTests.class})
|
||||||
|
@ -131,6 +127,39 @@ public class TestHRegionInfo {
|
||||||
assertTrue(adri.isOverlap(abri));
|
assertTrue(adri.isOverlap(abri));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link RegionInfo#isOverlap(RegionInfo[])}
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testIsOverlaps() {
|
||||||
|
byte[] a = Bytes.toBytes("a");
|
||||||
|
byte[] b = Bytes.toBytes("b");
|
||||||
|
byte[] c = Bytes.toBytes("c");
|
||||||
|
byte[] d = Bytes.toBytes("d");
|
||||||
|
byte[] e = Bytes.toBytes("e");
|
||||||
|
byte[] f = Bytes.toBytes("f");
|
||||||
|
org.apache.hadoop.hbase.client.RegionInfo ari =
|
||||||
|
org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME).
|
||||||
|
setEndKey(a).build();
|
||||||
|
org.apache.hadoop.hbase.client.RegionInfo abri =
|
||||||
|
org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME).
|
||||||
|
setStartKey(a).setEndKey(b).build();
|
||||||
|
org.apache.hadoop.hbase.client.RegionInfo eri =
|
||||||
|
org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME).
|
||||||
|
setEndKey(e).build();
|
||||||
|
org.apache.hadoop.hbase.client.RegionInfo cdri =
|
||||||
|
org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME).
|
||||||
|
setStartKey(c).setEndKey(d).build();
|
||||||
|
org.apache.hadoop.hbase.client.RegionInfo efri =
|
||||||
|
org.apache.hadoop.hbase.client.RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME).
|
||||||
|
setStartKey(e).setEndKey(f).build();
|
||||||
|
RegionInfo [] subsumes = new RegionInfo [] {ari, abri, eri};
|
||||||
|
assertTrue(abri.isOverlap(subsumes));
|
||||||
|
subsumes = new RegionInfo [] {ari, cdri, eri};
|
||||||
|
assertTrue(cdri.isOverlap(subsumes));
|
||||||
|
assertFalse(efri.isOverlap(subsumes));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPb() throws DeserializationException {
|
public void testPb() throws DeserializationException {
|
||||||
HRegionInfo hri = HRegionInfo.FIRST_META_REGIONINFO;
|
HRegionInfo hri = HRegionInfo.FIRST_META_REGIONINFO;
|
||||||
|
@ -159,9 +188,11 @@ public class TestHRegionInfo {
|
||||||
long modtime2 = getModTime(r);
|
long modtime2 = getModTime(r);
|
||||||
assertEquals(modtime, modtime2);
|
assertEquals(modtime, modtime2);
|
||||||
// Now load the file.
|
// Now load the file.
|
||||||
org.apache.hadoop.hbase.client.RegionInfo deserializedHri = HRegionFileSystem.loadRegionInfoFileContent(
|
org.apache.hadoop.hbase.client.RegionInfo deserializedHri =
|
||||||
|
HRegionFileSystem.loadRegionInfoFileContent(
|
||||||
r.getRegionFileSystem().getFileSystem(), r.getRegionFileSystem().getRegionDir());
|
r.getRegionFileSystem().getFileSystem(), r.getRegionFileSystem().getRegionDir());
|
||||||
assertTrue(org.apache.hadoop.hbase.client.RegionInfo.COMPARATOR.compare(hri, deserializedHri) == 0);
|
assertEquals(0,
|
||||||
|
org.apache.hadoop.hbase.client.RegionInfo.COMPARATOR.compare(hri, deserializedHri));
|
||||||
HBaseTestingUtility.closeRegionAndWAL(r);
|
HBaseTestingUtility.closeRegionAndWAL(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue