| 827 | } |
| 828 | |
| 829 | std::vector<ChunkCheckpointState> CSRNodeGroup::checkpointColumnInRegion(const UniqLock& lock, |
| 830 | column_id_t columnID, const CSRNodeGroupCheckpointState& csrState, |
| 831 | const CSRRegion& region) const { |
| 832 | const auto* txn = csrState.transaction ? csrState.transaction : &DUMMY_CHECKPOINT_TRANSACTION; |
| 833 | const auto leftCSROffset = csrState.oldHeader->getStartCSROffset(region.leftNodeOffset); |
| 834 | DASSERT(leftCSROffset == csrState.newHeader->getStartCSROffset(region.leftNodeOffset)); |
| 835 | const auto rightCSROffset = csrState.oldHeader->getEndCSROffset(region.rightNodeOffset); |
| 836 | const auto numOldRowsInRegion = rightCSROffset - leftCSROffset; |
| 837 | |
| 838 | Column* column = csrState.columns[columnID]; |
| 839 | LazySegmentScanner oldChunkScanner{*csrState.mm, column->getDataType().copy(), |
| 840 | enableCompression}; |
| 841 | auto chunkState = scanCommittedUpdates(txn, persistentChunkGroup->getColumnChunk(columnID), |
| 842 | column, oldChunkScanner, leftCSROffset, numOldRowsInRegion); |
| 843 | |
| 844 | const auto dummyChunkForNulls = ColumnChunkFactory::createColumnChunkData(*csrState.mm, |
| 845 | dataTypes[columnID].copy(), false, DEFAULT_VECTOR_CAPACITY, ResidencyState::IN_MEMORY); |
| 846 | dummyChunkForNulls->resetToAllNull(); |
| 847 | |
| 848 | std::vector<ChunkCheckpointState> ret; |
| 849 | |
| 850 | CheckpointReadCursor readCursor{oldChunkScanner, leftCSROffset}; |
| 851 | CheckpointWriteCursor writeCursor{leftCSROffset, *csrState.mm, column->getDataType(), ret}; |
| 852 | |
| 853 | // Copy per csr list from old chunk and merge with new insertions into the newChunkData. |
| 854 | for (auto nodeOffset = region.leftNodeOffset; nodeOffset <= region.rightNodeOffset; |
| 855 | nodeOffset++) { |
| 856 | const auto oldCSRLength = csrState.oldHeader->getCSRLength(nodeOffset); |
| 857 | |
| 858 | DASSERT(csrState.newHeader->getStartCSROffset(nodeOffset) == writeCursor.getCSROffset()); |
| 859 | DASSERT(csrState.oldHeader->getStartCSROffset(nodeOffset) == readCursor.getCSROffset()); |
| 860 | |
| 861 | // Copy old csr list with updates into the new chunk. |
| 862 | if (!region.hasPersistentDeletions) { |
| 863 | writeCSRListNoPersistentDeletions(readCursor, writeCursor, oldCSRLength); |
| 864 | } else { |
| 865 | writeCSRListWithPersistentDeletions(txn, readCursor, writeCursor, oldCSRLength, |
| 866 | *persistentChunkGroup); |
| 867 | } |
| 868 | // Merge in-memory insertions into the new chunk. |
| 869 | if (csrIndex) { |
| 870 | auto rows = csrIndex->indices[nodeOffset].getRows(); |
| 871 | // TODO(Guodong): Optimize here. if no deletions and has sequential rows, scan in |
| 872 | // range. |
| 873 | for (const auto row : rows) { |
| 874 | if (row == INVALID_ROW_IDX) { |
| 875 | continue; |
| 876 | } |
| 877 | auto [chunkIdx, rowInChunk] = StorageUtils::getQuotientRemainder(row, |
| 878 | StorageConfig::CHUNKED_NODE_GROUP_CAPACITY); |
| 879 | const auto chunkedGroup = chunkedGroups.getGroup(lock, chunkIdx); |
| 880 | writeInMemoryCSRInsertion(txn, writeCursor, *chunkedGroup, rowInChunk, columnID, |
| 881 | chunkState); |
| 882 | } |
| 883 | } |
| 884 | |
| 885 | const length_t numGaps = csrState.newHeader->getGapSize(nodeOffset); |
| 886 | const length_t numOldGaps = csrState.oldHeader->getGapSize(nodeOffset); |
nothing calls this directly
no test coverage detected