TableTuple *newTuple(TupleSchema *schema, int idx, long value) {
    TableTuple *tuple = new TableTuple(schema);
    char *data = new char[tuple->tupleLength()];
    memset(data, 0, tuple->tupleLength());
    tuple->move(data);

    tuple->setNValue(idx, ValueFactory::getBigIntValue(value));
    return tuple;
}
 void addRandomUniqueTuples(Table *table, int numTuples) {
     TableTuple tuple = table->tempTuple();
     ::memset(tuple.address() + 1, 0, tuple.tupleLength() - 1);
     for (int ii = 0; ii < numTuples; ii++) {
         tuple.setNValue(0, ValueFactory::getIntegerValue(m_primaryKeyIndex++));
         tuple.setNValue(1, ValueFactory::getIntegerValue(rand()));
         bool success = table->insertTuple(tuple);
         if (!success) {
             std::cout << "Failed to add random unique tuple" << std::endl;
             return;
         }
     }
 }
void CopyOnWriteContext::markTupleDirty(TableTuple tuple, bool newTuple) {
    /**
     * If this an update or a delete of a tuple that is already dirty then no further action is
     * required.
     */
    if (!newTuple && tuple.isDirty()) {
        return;
    }

    /**
     * If the table has been scanned already there is no need to continue marking tuples dirty
     * If the tuple is dirty then it has already been backed up.
     */
    if (m_finishedTableScan) {
        tuple.setDirtyFalse();
        return;
    }

    /**
     * Find out which block the address is contained in.
     */
    char *address = tuple.address();
#ifdef MEMCHECK
        BlockPair compP;
        compP.pair =  std::pair<char*, int>(address, 0);
        compP.tupleLength = tuple.tupleLength();
#else
    const BlockPair compP(address, 0);
#endif
    BlockPairVectorI i =
            std::lower_bound(m_blocks.begin(), m_blocks.end(), compP, pairAddressToPairAddressComparator);
    if (i == m_blocks.end()) {
        tuple.setDirtyFalse();
        return;
    }
#ifdef MEMCHECK
    const char *blockStartAddress = (*i).pair.first;
    const int blockIndex = (*i).pair.second;
    const char *blockEndAddress = blockStartAddress + tuple.tupleLength();
#else
    const char *blockStartAddress = (*i).first;
    const int blockIndex = (*i).second;
    const char *blockEndAddress = blockStartAddress + TABLE_BLOCKSIZE;
#endif

    if (address >= blockEndAddress || address < blockStartAddress) {
        /**
         * Tuple is in a block allocated after the start of COW
         */
        tuple.setDirtyFalse();
        return;
    }

    /**
     * Now check where this is relative to the COWIterator.
     */
    CopyOnWriteIterator *iter = reinterpret_cast<CopyOnWriteIterator*>(m_iterator.get());
    if (iter->needToDirtyTuple(blockIndex, address, newTuple)) {
        tuple.setDirtyTrue();
        /**
         * Don't back up a newly introduced tuple, just mark it as dirty.
         */
        if (!newTuple) {
            m_backedUpTuples->insertTupleNonVirtualWithDeepCopy(tuple, &m_pool);
        }
    } else {
        tuple.setDirtyFalse();
        return;
    }
}