[
https://issues.apache.org/jira/browse/PHOENIX-5996?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
chenglei resolved PHOENIX-5996.
-------------------------------
Fix Version/s: 4.16.0
5.1.0
Assignee: chenglei
Resolution: Fixed
> IndexRebuildRegionScanner.prepareIndexMutationsForRebuild may incorrectly
> delete index row when a delete and put mutation with the same timestamp
> -------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: PHOENIX-5996
> URL: https://issues.apache.org/jira/browse/PHOENIX-5996
> Project: Phoenix
> Issue Type: Bug
> Affects Versions: 5.1.0, 4.16.0
> Reporter: chenglei
> Assignee: chenglei
> Priority: Major
> Fix For: 5.1.0, 4.16.0
>
> Time Spent: 10m
> Remaining Estimate: 0h
>
> With PHOENIX-5748,
> {{IndexRebuildRegionScanner.prepareIndexMutationsForRebuild}} is responsible
> for generating index table mutations for rebuild.
> In the processing of data table mutations list, there can be a delete and put
> mutation with the same timestamp. If so, the delete and put are processed
> together in one iteration. First, the delete mutation is applied on the put
> mutation and current row state, and then the modified put mutation is
> processed.
> But when the {{modified put mutation}} is empty , even the current row state
> is not empty after the delete mutation is applied, the whole index row is
> deleted, just as following line 1191 in
> {{IndexRebuildRegionScanner.prepareIndexMutationsForRebuild}}:
> {code:java}
> 1189 } else {
> 1190 if (currentDataRowState != null) {
> 1191 Mutation del =
> indexMaintainer.buildRowDeleteMutation(indexRowKeyForCurrentDataRow,
> 1192 IndexMaintainer.DeleteType.ALL_VERSIONS,
> ts);
> 1193 indexMutations.add(del);
> 1194 // For the next iteration of the for loop
> 1195 currentDataRowState = null;
> 1196 indexRowKeyForCurrentDataRow = null;
> 1197 }
> 1198 }
> {code}
> I think above logical is wrong, when the current row state is not empty after
> the delete mutation is applied, we can not delete the whole index row, but
> instead we should reuse the logical of applying a delete mutation on current
> row state. I wrote a unit test in {{PrepareIndexMutationsForRebuildTest}} to
> produce the case:
> {code:java}
> @Test
> public void testPutDeleteOnSameTimeStampAndPutNullifiedByDelete() throws
> Exception {
> SetupInfo info = setup(
> TABLE_NAME,
> INDEX_NAME,
> "ROW_KEY VARCHAR, CF1.C1 VARCHAR, CF2.C2 VARCHAR",
> "CF2.C2",
> "ROW_KEY",
> "");
> Put dataPut = new Put(Bytes.toBytes(ROW_KEY));
> addCellToPutMutation(
> dataPut,
> Bytes.toBytes("CF2"),
> Bytes.toBytes("C2"),
> 1,
> Bytes.toBytes("v2"));
> addEmptyColumnToDataPutMutation(dataPut, info.pDataTable, 1);
>
> addCellToPutMutation(
> dataPut,
> Bytes.toBytes("CF1"),
> Bytes.toBytes("C1"),
> 2,
> Bytes.toBytes("v1"));
> addEmptyColumnToDataPutMutation(dataPut, info.pDataTable, 2);
> Delete dataDel = new Delete(Bytes.toBytes(ROW_KEY));
> addCellToDelMutation(
> dataDel,
> Bytes.toBytes("CF1"),
> null,
> 2,
> KeyValue.Type.DeleteFamily);
> List<Mutation> actualIndexMutations =
> IndexRebuildRegionScanner.prepareIndexMutationsForRebuild(
> info.indexMaintainer,
> dataPut,
> dataDel);
> List<Mutation> expectedIndexMutations = new ArrayList<>();
> byte[] idxKeyBytes = generateIndexRowKey("v2");
>
> Put idxPut1 = new Put(idxKeyBytes);
> addEmptyColumnToIndexPutMutation(idxPut1, info.indexMaintainer, 1);
> expectedIndexMutations.add(idxPut1);
>
> Put idxPut2 = new Put(idxKeyBytes);
> addEmptyColumnToIndexPutMutation(idxPut2, info.indexMaintainer, 2);
> expectedIndexMutations.add(idxPut2);
> assertEqualMutationList(expectedIndexMutations, actualIndexMutations);
> }
> {code}
--
This message was sent by Atlassian Jira
(v8.3.4#803005)