Package edu.brown.hstore.txns

Source Code of edu.brown.hstore.txns.DependencyInfo

package edu.brown.hstore.txns;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.voltdb.CatalogContext;
import org.voltdb.VoltTable;

import edu.brown.hstore.Hstoreservice.WorkFragment;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.pools.Poolable;
import edu.brown.utils.PartitionSet;
import edu.brown.utils.StringUtil;

/**
* A container for a single output dependency generated by a PlanFragment
* This can handle results from multiple partitions for the same fragment.
* @author pavlo
*/
public class DependencyInfo implements Poolable {
    private static final Logger LOG = Logger.getLogger(DependencyInfo.class);
    private static final LoggerBoolean debug = new LoggerBoolean();
    private static final LoggerBoolean trace = new LoggerBoolean();
    static {
        LoggerUtil.attachObserver(LOG, debug, trace);
    }
   
    // ----------------------------------------------------------------------------
    // INVOCATION DATA MEMBERS
    // ----------------------------------------------------------------------------
   
    private Long txn_id;
    private int round;
    private int stmt_counter = -1;
    private int stmt_index = -1;
    private int dependency_id = -1;
    private int params_hash = -1;
   
    /**
     * List of PartitionIds that we expect to get responses/results back
     */
    private final PartitionSet expectedPartitions;
   
    /**
     * The list of VoltTable results that have been sent back from partitions
     * We store it as a list so that we don't have to convert it for ExecutionSite
     */
    private final List<VoltTable> results = new ArrayList<VoltTable>();
   
    /**
     * The List of PartitionIds that we have successfully gotten back from partitions
     */
    private final PartitionSet resultPartitions;
   
    /**
     * We assume a 1-to-n mapping from DependencyInfos to blocked FragmentTaskMessages
     */
    private final Set<WorkFragment.Builder> blockedTasks = new HashSet<WorkFragment.Builder>();
   
    /**
     * If set to true, that means we have already released all the tasks that were
     * blocked on the results generated for this dependency
     */
    private boolean blockedTasksReleased = false;
   
    /**
     * Is the data for this dependency for intermediate results that
     * are only sent to another WorkFragment (as opposed to being sent back
     * to the transaction's control code).
     */
    private boolean internal = false;
   
    /**
     * Is the data for this dependency for a prefetched query. If this is
     * set to true, then this
     */
    private boolean prefetch = false;
   
    // ----------------------------------------------------------------------------
    // INITIALIZATION
    // ----------------------------------------------------------------------------
   
    /**
     * Constructor
     */
    protected DependencyInfo(CatalogContext catalogContext) {
        this.expectedPartitions = new PartitionSet(); // catalogContext.numberOfPartitions);
        this.resultPartitions = new PartitionSet(); // catalogContext.numberOfPartitions);
    }
   
    public void init(Long txn_id, int round, int stmt_counter, int stmt_index, int params_hash, int dependency_id) {
        if (debug.val)
            LOG.debug(String.format("#%s - Initializing DependencyInfo for %s in ROUND #%d",
                      txn_id, TransactionUtil.debugStmtDep(stmt_counter, dependency_id), round));
        this.txn_id = txn_id;
        this.round = round;
        this.stmt_counter = stmt_counter;
        this.stmt_index = stmt_index;
        this.params_hash = params_hash;
        this.dependency_id = dependency_id;
    }
   
    @Override
    public boolean isInitialized() {
        return (this.txn_id != null);
    }
   
    @Override
    public void finish() {
        this.txn_id = null;
        this.stmt_counter = -1;
        this.stmt_index = -1;
        this.dependency_id = -1;
        this.params_hash = -1;
        this.expectedPartitions.clear();
        this.blockedTasks.clear();
        this.blockedTasksReleased = false;
        this.internal = false;
        this.prefetch = false;
       
        this.results.clear();
        this.resultPartitions.clear();
    }
   
    /**
     * Special method for overriding this DependencyInfo's current round
     * and output dependency id. This is needed for prefetched WorkFragments
     * that don't have the real id when they were original created.
     * @param round
     * @param dependency_id
     * @param stmt_index
     */
    protected void prefetchOverride(int round, int dependency_id, int stmt_index) {
        this.round = round;
        this.dependency_id = dependency_id;
        this.stmt_index = stmt_index;
    }
   
    // ----------------------------------------------------------------------------
    // ACCESS METHODS
    // ----------------------------------------------------------------------------

    public Long getTransactionId() {
        return (this.txn_id);
    }
    protected int getRound() {
        return (this.round);
    }
    public int getStatementCounter() {
        return (this.stmt_counter);
    }
    public int getStatementIndex() {
        return (this.stmt_index);
    }
    public int getParameterSetHash() {
        return (this.params_hash);
    }
    public int getDependencyId() {
        return (this.dependency_id);
    }
   
    protected boolean inSameTxnRound(Long txn_id, int round) {
        return (txn_id.equals(this.txn_id) && this.round == round);
    }

    protected void markInternal() {
        if (debug.val)
            LOG.debug(String.format("#%s - Marking DependencyInfo for %s as internal",
                      this.txn_id, TransactionUtil.debugStmtDep(this.stmt_counter, this.dependency_id)));
        this.internal = true;
    }
    public boolean isInternal() {
        return (this.internal);
    }
   
    public void markPrefetch() {
        this.prefetch = true;
    }
    public void resetPrefetch() {
        this.prefetch = false;
    }
    public boolean isPrefetch() {
        return (this.prefetch);
    }
   
    // ----------------------------------------------------------------------------
    // API METHODS
    // ----------------------------------------------------------------------------
   
    /**
     * Add a FragmentTaskMessage this blocked until all of the partitions return results/responses
     * for this DependencyInfo
     * @param ftask
     */
    public void addBlockedWorkFragment(WorkFragment.Builder ftask) {
        if (trace.val) LOG.trace("Adding block FragmentTaskMessage for txn #" + this.txn_id);
        this.blockedTasks.add(ftask);
    }
   
    /**
     * Return the set of FragmentTaskMessages that are blocked until all of the partitions
     * return results/responses for this DependencyInfo
     * @return
     */
    protected Collection<WorkFragment.Builder> getBlockedWorkFragments() {
        return (this.blockedTasks);
    }
   
    /**
     * Gets the blocked tasks for this DependencyInfo and marks them as "released"
     * If the tasks have already been released, then the return value will be null;
     * @return
     */
    public Collection<WorkFragment.Builder> getAndReleaseBlockedWorkFragments() {
        if (this.blockedTasksReleased == false) {
            this.blockedTasksReleased = true;
            if (trace.val)
                LOG.trace(String.format("Unblocking %d FragmentTaskMessages for txn #%d",
                          this.blockedTasks.size(), this.txn_id));
            return (this.blockedTasks);
        }
        if (trace.val)
            LOG.trace(String.format("Ignoring duplicate release request for txn #%d", this.txn_id));
        return (null);
    }
   
    /**
     * Add a partition id that we expect to return a result/response for this dependency
     * @param partition
     */
    public void addPartition(int partition) {
        this.expectedPartitions.add(partition);
    }
    /**
     * <B>NOTE:</B> This should only be called for DEBUG purposes only
     */
    protected int getPartitionCount() {
        return (this.expectedPartitions.size());
    }
    /**
     * <B>NOTE:</B> This should only be called for DEBUG purposes only
     */
    protected PartitionSet getExpectedPartitions() {
        return (this.expectedPartitions);
    }
   
    /**
     * Add a result for a PartitionId.
     * Returns true if we have all of the results that we expected to get
     * from all of the partitions.
     * @param partition
     * @param result
     * @return
     */
    public boolean addResult(int partition, VoltTable result) {
        if (debug.val)
            LOG.debug(String.format("#%s - Storing RESULT for DependencyId #%d from partition %02d with %d tuples",
                      this.txn_id, this.dependency_id, partition, result.getRowCount()));
        assert(this.resultPartitions.contains(partition) == false) :
            String.format("Trying to add result %s into %s twice for %s!\n%s",
                          TransactionUtil.debugPartDep(partition, this.dependency_id),
                          this, this.txn_id, this.debug());
        assert(this.expectedPartitions.contains(partition)) :
            String.format("Unexpected partition result %s for %s!\n%s",
                          TransactionUtil.debugPartDep(partition, this.dependency_id),
                          this.txn_id, this.debug());
        this.results.add(result);
        this.resultPartitions.add(partition);
        return (this.expectedPartitions.size() == this.resultPartitions.size());
    }
   
    /**
     * Get the number of results that have arrived so far for this DependencyInfo
     * @return
     */
    protected int getResultsCount() {
        return (this.resultPartitions.size());
    }
    protected List<VoltTable> getResults() {
        return (this.results);
    }
    /**
     * Returns true if this DependencyInfo has all of the results
     * from the partitions that it was expected to get results from.
     * @return
     */
    protected boolean hasAllResults() {
        return (this.expectedPartitions.size() == this.resultPartitions.size());
    }
   
    /**
     * Return just the first result for this DependencyInfo
     * This should only be called to get back the results for the final VoltTable of a query
     * @return
     */
    public VoltTable getResult() {
        assert(this.resultPartitions.size() > 0) :
            String.format("There are no results available for %s\n%s", this, this.debug());
        assert(this.resultPartitions.size() == 1) :
            String.format("There are % results for %s\n" +
                      "-------\n%s\n" +
                      "-------\n%s",
                      this.resultPartitions.size(), this, this.results, this.debug());
        return (this.results.get(0));
    }
   
    /**
     * Returns true if the task blocked by this Dependency is now ready to run
     * @return
     */
    public boolean hasTasksReady() {
        if (debug.val)
            LOG.debug(String.format("txn #%d - hasTasksReady()\n" +
                                    "Block Tasks Not Empty? %s\n" +
                                    "# of Results:   %d\n" +
                                    "# of Partitions: %d",
                                    this.txn_id,
                                    this.blockedTasks.isEmpty() == false,
                                    this.resultPartitions.size(),
                                    this.expectedPartitions.size()));
        assert(this.resultPartitions.size() <= this.expectedPartitions.size()) :
            String.format("Invalid DependencyInfo state for txn #%d. " +
                      "There are %d results but %d partitions",
                      this.txn_id, this.resultPartitions.size(), this.expectedPartitions.size());
       
        return (this.blockedTasks.isEmpty() == false) &&
               (this.blockedTasksReleased == false) &&
               (this.resultPartitions.size() == this.expectedPartitions.size());
    }
   
    public boolean hasTasksBlocked() {
        return (this.blockedTasks.isEmpty() == false);
    }
   
    public boolean hasTasksReleased() {
        return (this.blockedTasksReleased);
    }
   
    // ----------------------------------------------------------------------------
    // DEBUG METHODS
    // ----------------------------------------------------------------------------

    @Override
    public String toString() {
        return String.format("DependencyInfo[#%d/hashCode:%d]",
                             this.dependency_id, this.hashCode());
    }
   
    public String debug() {
        if (this.isInitialized() == false) {
            return ("<UNINITIALIZED>");
        }
       
        String status = null;
        if (this.resultPartitions.size() == this.expectedPartitions.size()) {
            if (this.blockedTasksReleased == false) {
                status = "READY";
            } else {
                status = "RELEASED";
            }
        } else if (this.blockedTasks.isEmpty()) {
            status = "WAITING";
        } else {
            status = "BLOCKED";
        }
       
        Map<String, Object> m = new LinkedHashMap<String, Object>();
        m.put("- Internal", this.internal);
        m.put("- Prefetch", this.prefetch);
        m.put("- Round", this.round);
        m.put("- Stmt Counter", this.stmt_counter);
        m.put("- Stmt Index", this.stmt_index);
        m.put("- Parameters Hash", this.params_hash);
        m.put("- Expected Partitions", this.expectedPartitions);
        m.put("- Result Partitions", this.resultPartitions);
       
        Map<String, Object> inner = new LinkedHashMap<String, Object>();
        for (int i = 0; i < this.results.size(); i++) {
            VoltTable vt = this.results.get(i);
            inner.put(String.format("#%02d", i),
                      String.format("{%d tuples}", vt.getRowCount()))
        } // FOR
        m.put("- Results", inner);
        m.put("- Blocked", this.blockedTasks);
        m.put("- Status", status);

        return (this.toString() + "\n" + StringUtil.formatMaps(m).trim());
    }

}
TOP

Related Classes of edu.brown.hstore.txns.DependencyInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.