Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,6 +81,7 @@
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.ref.WeakReference;
import java.nio.charset.StandardCharsets;
import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
Expand DownExpand Up@@ -648,6 +649,20 @@ public void clearTableRegionCache(byte[] tableName) throws SQLException {
connection.clearRegionCache(TableName.valueOf(tableName));
}

public byte[] getNextRegionStartKey(HRegionLocation regionLocation, byte[] currentKey) throws IOException {
Comment thread
yanxinyi marked this conversation as resolved.
// in order to check the overlap/inconsistencies bad region info, we have to make sure
// the current endKey always increasing(compare the previous endKey)
if (Bytes.compareTo(regionLocation.getRegionInfo().getEndKey(), currentKey) <= 0
&& !Bytes.equals(currentKey, HConstants.EMPTY_START_ROW)
&& !Bytes.equals(regionLocation.getRegionInfo().getEndKey(), HConstants.EMPTY_END_ROW)) {
String regionNameString =
new String(regionLocation.getRegionInfo().getRegionName(), StandardCharsets.UTF_8);
throw new IOException(String.format(
"HBase region information overlap/inconsistencies on region %s", regionNameString));
}
return regionLocation.getRegionInfo().getEndKey();
}

@Override
public List<HRegionLocation> getAllTableRegions(byte[] tableName) throws SQLException {
/*
Expand All@@ -666,8 +681,8 @@ public List<HRegionLocation> getAllTableRegions(byte[] tableName) throws SQLExce
do {
HRegionLocation regionLocation = connection.getRegionLocation(
TableName.valueOf(tableName), currentKey, reload);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yanxinyi@dbwong are the locations in the regionLocations object always sorted ? If yes, then only it makes sense to compare if previous endKey is lesser than current endKey otherwise just comparing for equality will give us an answer if it is overlap.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this is the reason that we need to make sure the end key always increasing.

currentKey = getNextRegionStartKey(regionLocation, currentKey);
locations.add(regionLocation);
currentKey = regionLocation.getRegionInfo().getEndKey();
} while (!Bytes.equals(currentKey, HConstants.EMPTY_END_ROW));
return locations;
} catch (org.apache.hadoop.hbase.TableNotFoundException e) {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,8 @@
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.client.ClusterConnection;
Expand DownExpand Up@@ -157,6 +159,63 @@ public void testExceptionHandlingOnSystemNamespaceCreation() throws Exception {
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe one more test for the start/end keys.

@Test
public void testGetNextRegionStartKey() {
HRegionInfo mockHRegionInfo = org.mockito.Mockito.mock(HRegionInfo.class);
HRegionLocation mockRegionLocation = org.mockito.Mockito.mock(HRegionLocation.class);
ConnectionQueryServicesImpl mockCqsi = org.mockito.Mockito.mock(ConnectionQueryServicesImpl.class,
org.mockito.Mockito.CALLS_REAL_METHODS);
byte[] corruptedStartAndEndKey = "0x3000".getBytes();
byte[] corruptedDecreasingKey = "0x2999".getBytes();
byte[] notCorruptedStartKey = "0x2999".getBytes();
byte[] notCorruptedEndKey = "0x3000".getBytes();
byte[] notCorruptedNewKey = "0x3001".getBytes();
byte[] mockTableName = "dummyTable".getBytes();
when(mockRegionLocation.getRegionInfo()).thenReturn(mockHRegionInfo);
when(mockHRegionInfo.getRegionName()).thenReturn(mockTableName);

// comparing the current regionInfo endKey is equal to the previous endKey
// [0x3000, Ox3000) vs 0x3000
when(mockHRegionInfo.getStartKey()).thenReturn(corruptedStartAndEndKey);
when(mockHRegionInfo.getEndKey()).thenReturn(corruptedStartAndEndKey);
testGetNextRegionStartKey(mockCqsi, mockRegionLocation, corruptedStartAndEndKey, true);

// comparing the current regionInfo endKey is less than previous endKey
// [0x3000,0x2999) vs 0x3000
when(mockHRegionInfo.getStartKey()).thenReturn(corruptedStartAndEndKey);
when(mockHRegionInfo.getEndKey()).thenReturn(corruptedDecreasingKey);
testGetNextRegionStartKey(mockCqsi, mockRegionLocation, corruptedStartAndEndKey, true);

// comparing the current regionInfo endKey is greater than the previous endKey
// [0x3000,0x3000) vs 0x3001
when(mockHRegionInfo.getStartKey()).thenReturn(notCorruptedStartKey);
when(mockHRegionInfo.getEndKey()).thenReturn(notCorruptedNewKey);
testGetNextRegionStartKey(mockCqsi, mockRegionLocation, notCorruptedEndKey, false);

// test EMPTY_START_ROW
when(mockHRegionInfo.getStartKey()).thenReturn(HConstants.EMPTY_START_ROW);
when(mockHRegionInfo.getEndKey()).thenReturn(notCorruptedEndKey);
testGetNextRegionStartKey(mockCqsi, mockRegionLocation, HConstants.EMPTY_START_ROW, false);

//test EMPTY_END_ROW
when(mockHRegionInfo.getStartKey()).thenReturn(notCorruptedStartKey);
when(mockHRegionInfo.getEndKey()).thenReturn(HConstants.EMPTY_END_ROW);
testGetNextRegionStartKey(mockCqsi, mockRegionLocation, notCorruptedStartKey, false);
}

private void testGetNextRegionStartKey(ConnectionQueryServicesImpl mockCqsi,
HRegionLocation mockRegionLocation, byte[] key, boolean isCorrupted) {
try {
mockCqsi.getNextRegionStartKey(mockRegionLocation, key);
if (isCorrupted) {
fail();
}
} catch (IOException e) {
if (!isCorrupted) {
fail();
}
}
}
@Test
public void testSysMutexCheckReturnsFalseWhenTableAbsent() throws Exception {
// Override the getTableDescriptor() call to throw instead
Expand Down