Count rels by using CSR metadata, accounting for deletions and uncommitted data. This is more efficient than scanning through all edges.
| 31 | // Count rels by using CSR metadata, accounting for deletions and uncommitted data. |
| 32 | // This is more efficient than scanning through all edges. |
| 33 | bool CountRelTable::getNextTuplesInternal(ExecutionContext* context) { |
| 34 | if (hasExecuted) { |
| 35 | return false; |
| 36 | } |
| 37 | |
| 38 | auto transaction = Transaction::Get(*context->clientContext); |
| 39 | auto* memoryManager = context->clientContext->getDatabase()->getMemoryManager(); |
| 40 | |
| 41 | for (auto* relTable : relTables) { |
| 42 | if (dynamic_cast<ColumnarRelTableBase*>(relTable) != nullptr) { |
| 43 | totalCount += relTable->getNumTotalRows(transaction); |
| 44 | continue; |
| 45 | } |
| 46 | |
| 47 | // Get the RelTableData for the specified direction |
| 48 | auto* relTableData = relTable->getDirectedTableData(direction); |
| 49 | auto numNodeGroups = relTableData->getNumNodeGroups(); |
| 50 | auto* csrLengthColumn = relTableData->getCSRLengthColumn(); |
| 51 | |
| 52 | // For each node group in the rel table |
| 53 | for (node_group_idx_t nodeGroupIdx = 0; nodeGroupIdx < numNodeGroups; nodeGroupIdx++) { |
| 54 | auto* nodeGroup = relTableData->getNodeGroup(nodeGroupIdx); |
| 55 | if (!nodeGroup) { |
| 56 | continue; |
| 57 | } |
| 58 | |
| 59 | auto& csrNodeGroup = nodeGroup->cast<CSRNodeGroup>(); |
| 60 | |
| 61 | // Count from persistent (checkpointed) data |
| 62 | if (auto* persistentGroup = csrNodeGroup.getPersistentChunkedGroup()) { |
| 63 | // Sum the actual relationship lengths from the CSR header instead of using |
| 64 | // getNumRows() which includes dummy rows added for CSR offset array gaps |
| 65 | auto& csrPersistentGroup = persistentGroup->cast<ChunkedCSRNodeGroup>(); |
| 66 | auto& csrHeader = csrPersistentGroup.getCSRHeader(); |
| 67 | |
| 68 | // Get the number of nodes in this CSR header |
| 69 | auto numNodes = csrHeader.length->getNumValues(); |
| 70 | if (numNodes == 0) { |
| 71 | continue; |
| 72 | } |
| 73 | |
| 74 | // Create an in-memory chunk to scan the CSR length column into |
| 75 | auto lengthChunk = |
| 76 | ColumnChunkFactory::createColumnChunkData(*memoryManager, LogicalType::UINT64(), |
| 77 | false /*enableCompression*/, StorageConfig::NODE_GROUP_SIZE, |
| 78 | ResidencyState::IN_MEMORY, false /*initializeToZero*/); |
| 79 | |
| 80 | // Initialize scan state and scan the length column from disk |
| 81 | ChunkState chunkState; |
| 82 | csrHeader.length->initializeScanState(chunkState, csrLengthColumn); |
| 83 | csrLengthColumn->scan(chunkState, lengthChunk.get(), 0 /*offsetInChunk*/, numNodes); |
| 84 | |
| 85 | // Sum all the lengths |
| 86 | auto* lengthData = reinterpret_cast<const uint64_t*>(lengthChunk->getData()); |
| 87 | row_idx_t groupRelCount = 0; |
| 88 | for (offset_t i = 0; i < numNodes; ++i) { |
| 89 | groupRelCount += lengthData[i]; |
| 90 | } |
nothing calls this directly
no test coverage detected