-
Notifications
You must be signed in to change notification settings - Fork 1k
PHOENIX-5658 IndexTool to verify index rows inline #672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
gjacoby126
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, mostly nits.
phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
Show resolved
Hide resolved
phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java
Outdated
Show resolved
Hide resolved
phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java
Outdated
Show resolved
Hide resolved
phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java
Outdated
Show resolved
Hide resolved
phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java
Outdated
Show resolved
Hide resolved
phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java
Outdated
Show resolved
Hide resolved
phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java
Outdated
Show resolved
Hide resolved
phoenix-core/src/main/java/org/apache/phoenix/mapreduce/index/IndexTool.java
Outdated
Show resolved
Hide resolved
phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java
Outdated
Show resolved
Hide resolved
phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java
Outdated
Show resolved
Hide resolved
phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java
Outdated
Show resolved
Hide resolved
phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java
Outdated
Show resolved
Hide resolved
phoenix-core/src/main/java/org/apache/phoenix/mapreduce/index/IndexTool.java
Outdated
Show resolved
Hide resolved
phoenix-core/src/main/java/org/apache/phoenix/coprocessor/IndexRebuildRegionScanner.java
Outdated
Show resolved
Hide resolved
phoenix-core/src/main/java/org/apache/phoenix/coprocessor/IndexRebuildRegionScanner.java
Outdated
Show resolved
Hide resolved
priyankporwal
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks @kadirozde!
| } else if (Bytes.compareTo(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength(), | ||
| IndexTool.ERROR_MESSAGE_BYTES, 0, IndexTool.ERROR_MESSAGE_BYTES.length) == 0) { | ||
| errorMessageCell = cell; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: extra line
| null, -1, true, false); | ||
| // The index tool output table should report that there is a missing index row | ||
| Cell cell = getErrorMessageFromIndexToolOutputTable(conn, dataTableFullName, "_IDX_" + dataTableFullName); | ||
| byte[] expectedValueBytes = Bytes.toBytes("Missing index rows - Expected: 1 Actual: 0"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally could be columns for expected rows and actual rows and could check that, but that can be future work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a test for the mismatch on the column value in the following test for the only-verify option. It is almost impossible to generate missing columns or wrong column values with the verify option since index rows are corrected during rebuild
| IndexRegionObserver.setIgnoreIndexRebuildForTesting(false); | ||
| Admin admin = conn.unwrap(PhoenixConnection.class).getQueryServices().getAdmin(); | ||
| TableName indexToolOutputTable = TableName.valueOf(IndexTool.OUTPUT_TABLE_NAME_BYTES); | ||
| admin.disableTable(indexToolOutputTable); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
disabling / dropping takes time, and this test suite uses its own cluster -- any reason we need to drop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having an empty output table to start with simplifies the tests.
| if (directApi) { | ||
| args.add("-direct"); | ||
| } | ||
| if (verify) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if I pass in verify=true, onlyVerify=true? Shouldn't there be an exception?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add an assert here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After more thinking on this, I should not add an assert here as it is acceptable for the implementation to set both at this moment
| String errorMsg) { | ||
| try (Table hTable = ServerUtil.ConnectionFactory.getConnection(ServerUtil.ConnectionType.INDEX_WRITER_CONNECTION, | ||
| env).getTable(TableName.valueOf(IndexTool.OUTPUT_TABLE_NAME))) { | ||
| byte[] rowKey = new byte[Long.BYTES]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the row key also have the table being rebuilt? What if rebuilds are going on simultaneously on two different tables? Unlikely they'd be exact same ms, but possible.
Also, if the row key is just a timestamp, you'll hotspot (though hopefully this table will be low volume)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is possible but very unlikely to get the same timestamp especially when IndexTool runs are not automated. I intentionally chose a very simple row key to make the table human readable and easy to query using the HBase shell. There will be one table row for each mismatch row. The excepted volume will be low. I suggest not to optimize this for very unlikely scenarios.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about this again. Because of the "only-verify" option where the tool reports every mismatch row instead of just one, I need to make the row key unique. So, I am thinking about including the data row key in the in the row key for the output table.
| byte[] qualifier = CellUtil.cloneQualifier(expectedCell); | ||
| Cell actualCell = indexRow.getColumnLatestCell(family, qualifier); | ||
| if (actualCell == null) { | ||
| exceptionMessage = "Index verify failed - Missing cell " + indexHTable.getName(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: some extract methods around here would make this easier to read. maybe one function for cell not found and another for checking all the columns?
| scan.setTimeRange(0, scn); | ||
| scan.setAttribute(BaseScannerRegionObserver.INDEX_REBUILD_PAGING, TRUE_BYTES); | ||
| if (getVerifyIndex(configuration)) { | ||
| scan.setAttribute(BaseScannerRegionObserver.INDEX_REBUILD_VERIFY, TRUE_BYTES); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what happens if both set?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Verify wins
|
|
||
| if (verify) { | ||
| PhoenixConfigurationUtil.setVerifyIndex(configuration, true); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if both set?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if both "verify" and "only-verify" are set then as the help for the command says the only-verify option will be ignored: "To verify every data table row has the corresponding index row with the correct content (without building the index table). If the verify option is set then the only-verify option will be ignored");
| } | ||
| HTableDescriptor tableDescriptor = new | ||
| HTableDescriptor(TableName.valueOf(OUTPUT_TABLE_NAME)); | ||
| tableDescriptor.setValue("DISABLE_TABLE_SOR", "true"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a property that open source HBase or Phoenix recognizes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will remove it in the open source versions.
| int length = Long.BYTES + dataRowKey.length; | ||
| rowKey = new byte[length]; | ||
| Bytes.putLong(rowKey, 0, scan.getTimeRange().getMax()); | ||
| for (int i = Long.BYTES, j = 0; i < length; i++, j++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: System.arraycopy() might perform better than byte-by-byte copy. I assume it's java equivalent of memcpy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See also Bytes.putBytes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both suggestions work. I will go with Bytes.putBytes as it makes the code more readable.
gjacoby126
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1, thanks @kadirozde
…r crash (apache#672) * PHOENIX-6504 Ban thirdparty guava imports to prevent RegionServer crash * Remove thirdparty guava from phoenix-pherf
IndexTool uses UngroupedAggregateRegionObserver and IndexRegionObserver coprocessors to build an index table on the server side. UngroupedAggregateRegionObserver scans a data table regions and reconstructs the put mutations for each scanned row and applies them on the data table with the REPLAY_INDEX_REBUILD_WRITES option. These mutations are then only used to rebuild index rows by IndexRegionObserver. This PR adds an inline verification feature to UngroupedAggregateRegionObserver which reads these index rows and verifies their content to make sure they are build correctly.