private void getLastRowVersionInMaxLookbackWindow()

in phoenix-core-server/src/main/java/org/apache/phoenix/coprocessor/CompactionScanner.java [2285:2480]


        private void getLastRowVersionInMaxLookbackWindow(List<Cell> result,
                List<Cell> lastRowVersion, List<Cell> retainedCells, List<Cell> emptyColumn) {
            long maxLookbackWindowStart = rowContext.getMaxLookbackWindowStart();
            Cell currentColumnCell = null;
            Cell deleteFamilyCell = null;
            deleteFamilyVersionCellList.clear();
            top:
            for (int index = 0; index < result.size(); index++) {
                Cell cell = result.get(index);
                if (cell.getTimestamp() > maxLookbackWindowStart) {
                    // All cells within the max lookback window are retained. Here we retain all
                    // except the ones at the lower edge of the window. Those will be included in
                    // the last row version in the rest of the body of the loop
                    retainedCells.add(cell);
                    continue;
                }
                // The following section of the for loop processes an entire column in each
                // iteration, that is, all cell versions for a given column will be processed in
                // each iteration. Please note delete family markers (DeleteFamily and
                // DeleteFamilyVersion) has their own column with the null column qualifier. The
                // delete family column cells always forms the first column in a row of cells for a
                // given column family
                if (currentColumnCell == null) {
                    // This is the first column. If the row has any delete family markers, they will
                    // be in the first column
                    currentColumnCell = cell;
                    if (cell.getType() == Cell.Type.DeleteFamily) {
                        // The first delete family marker at the edge or outside the max lookback
                        // window is DeleteFamily.
                        deleteFamilyCell = cell;
                        if (cell.getTimestamp() == maxLookbackWindowStart) {
                            // it is at the edge of the window.So we need to include it in the last
                            // row version
                            lastRowVersion.add(cell);
                        } else if (!major) {
                            // Retain the delete markers if the compaction is not major
                            retainedCells.add(cell);
                        }
                        // Skip the rest of the delete family cells
                        index = skipColumn(result, currentColumnCell, retainedCells, index);
                        continue;
                    } else if (cell.getType() == Cell.Type.DeleteFamilyVersion) {
                        deleteFamilyVersionCellList.add(cell);
                        if (cell.getTimestamp() == maxLookbackWindowStart) {
                            lastRowVersion.add(cell);
                        } else if (!major) {
                            // Retain the delete markers if the compaction is not major
                            retainedCells.add(cell);
                        }
                        // Each DeleteFamilyVersion can delete at most one row version. There can be
                        // multiple of them, and we need to process each separately, and thus we
                        // need to track them in a list
                        for (int i = index + 1; i < result.size(); i++) {
                            cell = result.get(i);
                            if (cell.getType() == Cell.Type.DeleteFamilyVersion) {
                                index++;
                                deleteFamilyVersionCellList.add(cell);
                                if (!major) {
                                    // Delete markers are retained if the compaction is not a major
                                    // compaction
                                    retainedCells.add(cell);
                                }
                            } else if (cell.getType() == Cell.Type.DeleteFamily) {
                                // After one or more DeleteFamilyVersion markers, there is a
                                // DeleteFamily marker. This marker deletes the rest of the cells
                                // and thus no need to process further delete family markers. Thus,
                                // we skip them using skipColumn
                                index++;
                                deleteFamilyCell = cell;
                                if (!major) {
                                    retainedCells.add(cell);
                                }
                                // Skip the rest of the delete family cells
                                index = skipColumn(result, currentColumnCell, retainedCells, index);
                                continue top;
                            } else {
                                // Column changed as the current cell is not a delete family cell.
                                // Go back to the beginning of the for loop
                                continue top;
                            }
                        }
                        // All the cells in a row are processed
                        break top;
                    }
                }
                // All delete family markers are scanned and recorded above if there was any. Please
                // note when we do region level compaction, each column family will have their owm
                // delete family markers. Phoenix inserts the same set of delete markers to each
                // column family. So, we need to keep track of the delete family markers of the
                // first column family but apply these delete markers to all column families
                currentColumnCell = cell;
                // Is this cell masked by a delete column family version
                if (!deleteFamilyVersionCellList.isEmpty()) {
                    // There could be back to back delete family version markers and thus we need a
                    // loop to check it
                    for (Cell deleteFamilyVersionCell : deleteFamilyVersionCellList) {
                        if (cell.getTimestamp() > deleteFamilyVersionCell.getTimestamp()) {
                            break;
                        }
                        if (cell.getTimestamp() == deleteFamilyVersionCell.getTimestamp()) {
                            // It is masked
                            if (cell.getType() != Cell.Type.Put) {
                                if (cell.getTimestamp() == maxLookbackWindowStart) {
                                    lastRowVersion.add(cell);
                                } else if (!major) {
                                    // Retain the delete markers if the compaction is not major
                                    retainedCells.add(cell);
                                }
                            }
                            if (index + 1 < result.size()) {
                                cell = result.get(index + 1);
                                if (!CellUtil.matchingColumn(cell, currentColumnCell)) {
                                    continue top;
                                }
                                index++;
                            } else {
                                break top;
                            }
                        }
                    }
                }
                if (deleteFamilyCell != null
                        && deleteFamilyCell.getTimestamp() >= cell.getTimestamp()) {
                    // This column is deleted by a delete family marker. Skip this column
                    if (cell.getType() != Cell.Type.Put) {
                        if (cell.getTimestamp() == maxLookbackWindowStart) {
                            lastRowVersion.add(cell);
                        } else if (!major) {
                            // Retain the delete markers if the compaction is not major
                            retainedCells.add(cell);
                        }
                    }
                    index = skipColumn(result, currentColumnCell, retainedCells, index);
                    continue top;
                }
                // Process back-to-back deleted cell versions. Phoenix currently does not use delete
                // cell version markers. This processing should not happen and is added for
                // completeness
                while (cell.getType() == Cell.Type.Delete) {
                    if (cell.getTimestamp() == maxLookbackWindowStart) {
                        lastRowVersion.add(cell);
                    } else if (!major) {
                        retainedCells.add(cell);
                    }
                    if (index + 1 < result.size()) {
                        Cell nextCell = result.get(index + 1);
                        if (!CellUtil.matchingColumn(currentColumnCell, nextCell)) {
                            continue top;
                        }
                        // Increment index by one as the delete cell should be consumed
                        index++;
                        if (nextCell.getType() == Cell.Type.Put
                                && cell.getTimestamp() == nextCell.getTimestamp()) {
                            // This put cell is masked by the delete marker
                            index++;
                            if (index < result.size()) {
                                cell = result.get(index);
                            } else {
                                break top;
                            }
                        }
                    } else {
                        break top;
                    }
                }
                if (cell.getType() == Cell.Type.DeleteColumn) {
                    // The rest of the column is masked by this delete column cell
                    if (cell.getTimestamp() == maxLookbackWindowStart) {
                        lastRowVersion.add(cell);
                    } else if (!major) {
                        retainedCells.add(cell);
                    }
                    index = skipColumn(result, currentColumnCell, retainedCells, index);
                    continue top;
                }
                if (cell.getType() == Cell.Type.Put) {
                    lastRowVersion.add(cell);
                    if (ScanUtil.isEmptyColumn(cell, emptyCF, emptyCQ)) {
                        index = addEmptyColumn(result, currentColumnCell, index, emptyColumn);
                    } else {
                        index = skipColumn(result, currentColumnCell, retainedCells, index);
                    }
                    continue top;
                }
                // We can visit another delete family column for another column family if we are
                // doing region level compaction. In that case, we should also retain delete family
                // markers from that column family here. So we need to check if the cell type is
                // DeleteFamily or DeleteFamilyVersion, the column family is the store under
                // compaction and the compaction is not a major compaction.
                if (!major && CellUtil.matchingFamily(cell, storeColumnFamily) &&
                        (cell.getType() == Cell.Type.DeleteFamily
                                || cell.getType() == Cell.Type.DeleteFamilyVersion)) {
                    index = skipColumn(result, currentColumnCell, retainedCells, index);
                }
            }
        }