/** * Iterate through the table blocks until all the active tuples have been found. Skip dirty tuples * and mark them as clean so that they can be copied during the next snapshot. */ bool CopyOnWriteIterator::next(TableTuple &out) { assert(m_currentBlock != NULL); while (true) { if (m_blockOffset >= m_currentBlock->unusedTupleBoundry()) { if (m_blockIterator == m_end) { m_table->snapshotFinishedScanningBlock(m_currentBlock, TBPtr()); break; } m_table->snapshotFinishedScanningBlock(m_currentBlock, m_blockIterator.data()); m_location = m_blockIterator.key(); m_currentBlock = m_blockIterator.data(); assert(m_currentBlock->address() == m_location); m_blockIterator.data() = TBPtr(); m_blockOffset = 0; m_blockIterator++; } assert(m_location < m_currentBlock.get()->address() + m_table->m_tableAllocationSize); assert(m_location < m_currentBlock.get()->address() + (m_table->m_tupleLength * m_table->m_tuplesPerBlock)); assert (out.sizeInValues() == m_table->columnCount()); m_blockOffset++; out.move(m_location); const bool active = out.isActive(); const bool dirty = out.isDirty(); // Return this tuple only when this tuple is not marked as deleted and isn't dirty if (active && !dirty) { out.setDirtyFalse(); m_location += m_tupleLength; return true; } else { out.setDirtyFalse(); m_location += m_tupleLength; } } return false; }
/** * Iterate through the table blocks until all the active tuples have been found. Skip dirty tuples * and mark them as clean so that they can be copied during the next snapshot. */ bool CopyOnWriteIterator::next(TableTuple &out) { if (m_currentBlock == NULL) { return false; } while (true) { if (m_blockOffset >= m_currentBlock->unusedTupleBoundary()) { if (m_blockIterator == m_end) { m_surgeon->snapshotFinishedScanningBlock(m_currentBlock, TBPtr()); break; } m_surgeon->snapshotFinishedScanningBlock(m_currentBlock, m_blockIterator.data()); char *finishedBlock = m_currentBlock->address(); m_location = m_blockIterator.key(); m_currentBlock = m_blockIterator.data(); assert(m_currentBlock->address() == m_location); m_blockOffset = 0; // Remove the finished block from the map so that it can be released // back to the OS if all tuples in the block is deleted. // // This invalidates the iterators, so we have to get new iterators // using the current block's start address. m_blockIterator has to // point to the next block, hence the upper_bound() call. m_blocks.erase(finishedBlock); m_blockIterator = m_blocks.upper_bound(m_currentBlock->address()); m_end = m_blocks.end(); } assert(m_location < m_currentBlock.get()->address() + m_table->getTableAllocationSize()); assert(m_location < m_currentBlock.get()->address() + (m_table->getTupleLength() * m_table->getTuplesPerBlock())); assert (out.columnCount() == m_table->columnCount()); m_blockOffset++; out.move(m_location); const bool active = out.isActive(); const bool dirty = out.isDirty(); if (dirty) m_skippedDirtyRows++; if (!active) m_skippedInactiveRows++; // Return this tuple only when this tuple is not marked as deleted and isn't dirty if (active && !dirty) { out.setDirtyFalse(); m_location += m_tupleLength; return true; } else { out.setDirtyFalse(); m_location += m_tupleLength; } } return false; }
CopyOnWriteIterator::CopyOnWriteIterator( PersistentTable *table, TBMapI start, TBMapI end) : m_table(table), m_blockIterator(start), m_end(end), m_tupleLength(table->m_tupleLength), m_location(NULL), m_blockOffset(0), m_currentBlock(NULL) { //Prime the pump m_table->snapshotFinishedScanningBlock(m_currentBlock, m_blockIterator.data()); m_location = m_blockIterator.key(); m_currentBlock = m_blockIterator.data(); m_blockIterator.data() = TBPtr(); m_blockOffset = 0; m_blockIterator++; }
/** * Internal method that handles transitions between blocks and * returns true as long as tuples are available. */ bool ElasticScanner::continueScan() { if (!m_scanComplete) { // First block or end of block? if (m_currentBlockPtr == NULL || m_tupleIndex >= m_currentBlockPtr->unusedTupleBoundry()) { // No more blocks? m_scanComplete = (m_blockIterator == m_blockEnd); if (!m_scanComplete) { // Shift to the next block. m_tuplePtr = m_blockIterator.key(); m_currentBlockPtr = m_blockIterator.data(); m_scannedBlocks.insert(m_currentBlockPtr); assert(m_currentBlockPtr->address() == m_tuplePtr); m_blockIterator.data() = TBPtr(); m_tupleIndex = 0; m_blockIterator++; } } } return !m_scanComplete; }