• Donald H. (Donnie) Pinkston, III's avatar
    Design document and supporting code for lab 5 · 391659b2
    Donald H. (Donnie) Pinkston, III authored
    Supporting code includes some SQL tests with scalar subqueries, with
    some being correlated and others not.  Also, a buggy materialize-node
    implementation for those who want to tinker with making IN/NOT IN
    subqueries more efficient -  but the bugs will need to be fixed.
    391659b2
MaterializeNode.java 4.46 KB
package edu.caltech.nanodb.plannodes;


import java.util.ArrayList;
import java.util.List;

import edu.caltech.nanodb.expressions.OrderByExpression;
import edu.caltech.nanodb.expressions.TupleLiteral;
import edu.caltech.nanodb.relations.Tuple;


/**
 * <p>
 * This plan-node materializes the results of a child plan-node in memory.
 * The tuples of the child plan-node are fetched on-demand (not all at once
 * at the start of plan-node execution), and are cached within this plan-node.
 * If the child plan produces disk-backed tuples, this plan-node caches a copy
 * of the tuple so that the disk-backed tuple can be unpinned.
 * </p>
 * <p>
 * Note that a more typical implementation of a "materialize" node would have
 * a maximum in-memory footprint, and would store tuples to a temporary disk
 * file when this maximum memory size is reached.  However, the memory
 * allocation for in-memory tuples is not managed by the Buffer Manager, so it
 * really isn't possible for the materialize node to provide this kind of
 * functionality.
 * </p>
 */
public class MaterializeNode extends PlanNode {

    /**
     * This collection holds the tuples that have been generated by the child
     * plan so far.
     */
    private ArrayList<Tuple> tuples;


    /**
     * This field stores the index of the "current tuple" as the materialized
     * results are traversed.
     */
    private int currentTupleIndex;


    /** This field stores the index of the tuple when a position is marked. */
    private int markedTupleIndex;



    /**
     * When this flag is true, the child plan-node has finished generating
     * all of its results.
     */
    private boolean childNodeFinished;



    public MaterializeNode(PlanNode leftChild) {
        super(leftChild);
    }


    @Override
    public List<OrderByExpression> resultsOrderedBy() {
        return leftChild.resultsOrderedBy();
    }


    @Override
    public boolean supportsMarking() {
        return true;
    }


    @Override
    public void prepare() {
        leftChild.prepare();

        schema = leftChild.getSchema();
        stats = leftChild.getStats();
        cost = leftChild.getCost();

        tuples = new ArrayList<>();
        currentTupleIndex = -1;
        markedTupleIndex = -1;
        childNodeFinished = false;
    }


    @Override
    public Tuple getNextTuple() {
        Tuple tup = null;

        assert currentTupleIndex >= -1;
        assert currentTupleIndex <= tuples.size();

        if (currentTupleIndex + 1 < tuples.size()) {
            // Moving forward the "current tuple" index will stay within the
            // tuples we have so far.
            currentTupleIndex++;
            tup = tuples.get(currentTupleIndex);
        }
        else {
            // Moving forward the "current tuple" index will move beyond the
            // tuples we have so far.  Need to see if we have consumed all
            // child tuples yet.

            if (!childNodeFinished) {
                // Try to fetch another tuple from the child plan-node, if
                // there is one.
                tup = leftChild.getNextTuple();
                if (tup != null) {
                    if (tup.isDiskBacked()) {
                        // Make an in-memory version of the tuple we can cache.
                        Tuple copy = new TupleLiteral(tup);
                        tup.unpin();
                        tup = copy;
                    }

                    tuples.add(tup);
                    currentTupleIndex++;
                }
                else {
                    // The child has no more tuples.
                    childNodeFinished = true;
                }

                assert currentTupleIndex <= tuples.size();
            }
        }

        return tup;
    }


    @Override
    public void markCurrentPosition() {
        markedTupleIndex = currentTupleIndex;
    }

    @Override
    public void resetToLastMark() {
        currentTupleIndex = markedTupleIndex;
    }

    @Override
    public void cleanUp() {
        leftChild.cleanUp();

        tuples = null;
        currentTupleIndex = -1;
    }

    @Override
    public String toString() {
        return "Materialize";
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof MaterializeNode) {
            MaterializeNode other = (MaterializeNode) obj;
            return leftChild.equals(other.leftChild);
        }

        return false;
    }

    @Override
    public int hashCode() {
        return leftChild.hashCode();
    }
}