Package edu.brown.hstore.txns

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

package edu.brown.hstore.txns;

import org.apache.log4j.Logger;
import org.voltdb.ClientResponseImpl;
import org.voltdb.ParameterSet;
import org.voltdb.VoltTable;
import org.voltdb.VoltTableRow;
import org.voltdb.catalog.Procedure;
import org.voltdb.catalog.Table;

import com.google.protobuf.RpcCallback;

import edu.brown.catalog.CatalogUtil;
import edu.brown.hstore.HStoreSite;
import edu.brown.hstore.Hstoreservice.Status;
import edu.brown.hstore.Hstoreservice.TransactionMapResponse;
import edu.brown.hstore.Hstoreservice.TransactionReduceResponse;
import edu.brown.hstore.callbacks.SendDataCallback;
import edu.brown.hstore.callbacks.RemoteFinishCallback;
import edu.brown.hstore.callbacks.TransactionMapCallback;
import edu.brown.hstore.callbacks.TransactionMapWrapperCallback;
import edu.brown.hstore.callbacks.TransactionReduceCallback;
import edu.brown.hstore.callbacks.TransactionReduceWrapperCallback;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.utils.PartitionSet;

/**
* Special transaction state object for MapReduce jobs
* @author pavlo
* @author xin
*/
public class MapReduceTransaction extends LocalTransaction {
    private static final Logger LOG = Logger.getLogger(MapReduceTransaction.class);
    private static final LoggerBoolean debug = new LoggerBoolean();
    private static final LoggerBoolean trace = new LoggerBoolean();
    static {
        LoggerUtil.attachObserver(LOG, debug, trace);
    }
   
    private final LocalTransaction local_txns[];
    public int partitions_size;
   
    private VoltTable mapOutput[];
    private VoltTable reduceInput[];
    private VoltTable reduceOutput[];

    public enum State {
        MAP,
        SHUFFLE,
        REDUCE,
        FINISH;
    }

    /**
     * MapReduce Phases
     */
    private State mr_state = null;
   
    private Table mapEmit;
    private Table reduceEmit;
   
    /**
     * This is for non-blocking reduce executing in MapReduceHelperThread
     */
    public boolean basePartition_reduce_exec = false;
    public boolean basePartition_map_exec = false;
   
    // ----------------------------------------------------------------------------
    // CALLBACKS
    // ----------------------------------------------------------------------------

   
    /**
     */
    private final TransactionMapCallback map_callback;

    private final TransactionMapWrapperCallback mapWrapper_callback;
   
    private final SendDataCallback sendData_callback;
   
    private final TransactionReduceCallback reduce_callback;
   
    private final TransactionReduceWrapperCallback reduceWrapper_callback;
   
    private final RemoteFinishCallback cleanup_callback;

    /**
     * Constructor
     * @param hstore_site
     */
    public MapReduceTransaction(HStoreSite hstore_site) {
        super(hstore_site);
        // new local_txns
        this.partitions_size = this.hstore_site.getLocalPartitionIds().size();
        this.local_txns = new LocalTransaction[this.partitions_size];
        for (int i = 0; i < this.partitions_size; i++) {
            this.local_txns[i] = new LocalTransaction(hstore_site) {
                @Override
                public String toStringImpl() {
                    return MapReduceTransaction.this.toString() + "/" + this.base_partition;
                }
            };
        } // FOR
       
        // new mapout and reduce output talbes for each partition it wants to touch
        this.mapOutput = new VoltTable[this.partitions_size];
        this.reduceInput = new VoltTable[this.partitions_size];
        this.reduceOutput = new VoltTable[this.partitions_size];
               
        this.map_callback = new TransactionMapCallback(hstore_site);
        this.mapWrapper_callback = new TransactionMapWrapperCallback(hstore_site);
       
        this.sendData_callback = new SendDataCallback(hstore_site);
        //this.sendDataWrapper_callback = new SendDataWrapperCallback(hstore_site);
       
        this.reduce_callback = new TransactionReduceCallback(hstore_site);
        this.reduceWrapper_callback = new TransactionReduceWrapperCallback(hstore_site);
       
        this.cleanup_callback = new RemoteFinishCallback(hstore_site);
    }
   
   
    @Override
    public LocalTransaction init(Long txn_id,
                                 long initiateTime,
                                 long clientHandle,
                                 int base_partition,
                                 PartitionSet predict_touchedPartitions,
                                 boolean predict_readOnly,
                                 boolean predict_canAbort,
                                 Procedure catalog_proc,
                                 ParameterSet params,
                                 RpcCallback<ClientResponseImpl> client_callback) {
        super.init(txn_id,
                   initiateTime,
                   clientHandle,
                   base_partition,
                   predict_touchedPartitions,
                   predict_readOnly,
                   predict_canAbort,
                   catalog_proc,
                   params,
                   client_callback);
       
        // Intialize MapReduce properties
        this.mapEmit = hstore_site.getCatalogContext().getTableByName(catalog_proc.getMapemittable());
        this.reduceEmit = hstore_site.getCatalogContext().getTableByName(catalog_proc.getReduceemittable());
        if (debug.val) {
            LOG.debug(" CatalogUtil.getVoltTable(thisMapEmit): -> " + catalog_proc.getMapemittable());
            LOG.debug("MapReduce LocalPartitionIds: " + this.hstore_site.getLocalPartitionIds());
        }
       
        // Get the Table catalog object for the map/reduce outputs
        // For each partition there should be a map/reduce output voltTable
        for (int partition : this.hstore_site.getLocalPartitionIds()) {
            if (debug.val) LOG.debug(String.format("Partition[%d] -> Offset[%d]", partition, partition));
            this.local_txns[partition].init(this.txn_id,
                                         initiateTime,
                                         this.client_handle,
                                         partition,
                                         hstore_site.getCatalogContext().getPartitionSetSingleton(partition),
                                         this.predict_readOnly,
                                         this.predict_abortable,
                                         catalog_proc,
                                         params,
                                         null);
            this.local_txns[partition].markMapReduce();
           
            // init map/reduce Output for each partition
            assert(this.mapEmit != null): "mapEmit has not been initialized\n ";
            assert(this.reduceEmit != null): "reduceEmit has not been initialized\n ";
            this.mapOutput[partition] = CatalogUtil.getVoltTable(this.mapEmit);
            this.reduceInput[partition] = CatalogUtil.getVoltTable(this.mapEmit);
            this.reduceOutput[partition] = CatalogUtil.getVoltTable(this.reduceEmit);
           
        } // FOR
       
        this.setMapPhase();
        this.map_callback.init(this);
        assert(this.map_callback.isInitialized()) : "Unexpected error for " + this;
        this.reduce_callback.init(this);
        assert(this.reduce_callback.isInitialized()) : "Unexpected error for " + this;
       
        // Initialize the TransactionCleanupCallback if this txn's base partition
        // is not at this HStoreSite.
        if (this.hstore_site.isLocalPartition(base_partition) == false) {
            this.cleanup_callback.init(this, this.hstore_site.getLocalPartitionIds());
        }
       
        if (debug.val) LOG.info("Invoked MapReduceTransaction.init() -> " + this);
        return (this);
    }

    public MapReduceTransaction init(Long txn_id,
                                     long initiateTime,
                                     long client_handle,
                                     int base_partition,
                                     Procedure catalog_proc,
                                     ParameterSet params) {
        this.init(txn_id,
                  initiateTime,
                  client_handle,
                  base_partition,
                  hstore_site.getCatalogContext().getAllPartitionIds(),
                  false,
                  true,
                  catalog_proc,
                  params,
                  null);
        LOG.info("Invoked MapReduceTransaction.init() -> " + this);
        assert(this.map_callback.isInitialized()) : "Unexpected error for " + this;
        //assert(this.sendData_callback.isInitialized()) : "Unexpected error for " + this;
        return (this);
    }
   
    @Override
    public void finish() {
        super.finish();
//        for (int i = 0; i < this.partitions_size; i++) {
//            this.local_txns[i].finish();
//        } // FOR
        this.mr_state = null;
       
        this.map_callback.finish();
        this.mapWrapper_callback.finish();
        this.sendData_callback.finish();
        this.reduce_callback.finish();
        this.reduceWrapper_callback.finish();
       
        this.basePartition_map_exec = false;
        this.basePartition_reduce_exec = false;
       
        // TODO(xin): Only call TransactionCleanupCallback.finish() if this txn's base
        //            partition is not at this HStoreSite.
        if (!this.hstore_site.isLocalPartition(this.base_partition)) {
            this.cleanup_callback.finish();
        }
       
       
        if(debug.val) LOG.debug("<MapReduceTransaction> this.reduceWrapper_callback.finish().......................");
        this.mapEmit = null;
        this.reduceEmit = null;
        this.mapOutput = null;
        this.reduceInput = null;
        this.reduceOutput = null;
    }
    /**
     * Store Data from MapOutput table into reduceInput table
     * ReduceInput table is the result of all incoming mapOutput table from other partitions
     * @see edu.brown.hstore.txns.AbstractTransaction#storeData(int, org.voltdb.VoltTable)
     */
    @Override
    public synchronized Status storeData(int partition, VoltTable vt) {
        VoltTable input = this.getReduceInputByPartition(partition);
       
        assert(input != null);
        if (debug.val)
            LOG.debug(String.format("StoreData into Partition #%d: RowCount=%d ",
                    partition, vt.getRowCount()));
       
        if (debug.val)
            LOG.debug(String.format("<StoreData, change to ReduceInputTable> to Partition:%d>\n %s",partition,vt));
        while (vt.advanceRow()) {
            VoltTableRow row = vt.fetchRow(vt.getActiveRowIndex());
            assert(row != null);
            input.add(row);
        }
        vt.resetRowPosition();
       
        return Status.OK;
    }
   
    /**
     * Get a LocalTransaction handle for a local partition
     *
     * @param partition
     * @return
     */
    public LocalTransaction getLocalTransaction(int partition) {
        return (this.local_txns[partition]);
    }
   
    // ----------------------------------------------------------------------------
    // ACCESS METHODS
    // ----------------------------------------------------------------------------
   
    @Override
    public boolean isDeletable() {
        if (this.cleanup_callback.allCallbacksFinished() == false) {
            if (trace.val)
                LOG.warn(String.format("%s - %s is not finished", this,
                         this.cleanup_callback.getClass().getSimpleName()));
            return (false);
        }
        return (super.isDeletable());
    }
   
    public boolean isBasePartitionMapExec() {
        return this.basePartition_map_exec;
    }

    public void markBasePartitionMapExec() {
        assert(this.basePartition_map_exec == false);
        this.basePartition_map_exec = true;
    }

    public boolean isBasePartitionReduceExec() {
        return this.basePartition_reduce_exec;
    }

    public void markBasePartitionReduceExec() {
        assert(this.basePartition_reduce_exec == false);
        this.basePartition_reduce_exec = true;
    }
   
    /*
     * Return the MapOutput Table schema
     */
   
    public boolean isMapPhase() {
        return (this.mr_state == State.MAP);
    }
  
    public boolean isShufflePhase() {
        return (this.mr_state == State.SHUFFLE);
    }
   
    public boolean isReducePhase() {
        return (this.mr_state == State.REDUCE);
    }
   
    public boolean isFinishPhase() {
        return (this.mr_state == State.FINISH);
    }
   
    public void setMapPhase() {
        assert (this.mr_state == null);
        this.mr_state = State.MAP;
    }

    public void setShufflePhase() {
        assert(this.isMapPhase());
        this.mr_state = State.SHUFFLE;
    }
   
    public void setReducePhase() {
        assert(this.isShufflePhase());
        this.mr_state = State.REDUCE;
    }
   
    public void setFinishPhase() {
        assert(this.isReducePhase());
        this.mr_state = State.FINISH;
    }
    /*
     * return the size of partitions that MapReduce Transaction will touch
     */
    public int getSize() {
        return partitions_size;
    }   
    public Table getMapEmit() {
        return mapEmit;
    }
    /*
     * Return the ReduceOutput Table schema
     */
   
    public Table getReduceEmit() {
       
        return reduceEmit;
    }

    public State getState() {
        return (this.mr_state);
    }
       
    public VoltTable[] getReduceOutput() {
        return this.reduceOutput;
    }
   
    public TransactionMapCallback getTransactionMapCallback() {
        return (this.map_callback);
    }

    public TransactionMapWrapperCallback getTransactionMapWrapperCallback() {
        assert(this.mapWrapper_callback.isInitialized());
        return (this.mapWrapper_callback);
    }
   
    public SendDataCallback getSendDataCallback() {
        return sendData_callback;
    }

    public TransactionReduceCallback getTransactionReduceCallback() {
        return (this.reduce_callback);
    }
   
    public TransactionReduceWrapperCallback getTransactionReduceWrapperCallback() {
        assert(this.reduceWrapper_callback.isInitialized());
        return (this.reduceWrapper_callback);
    }
   
    public void initTransactionMapWrapperCallback(RpcCallback<TransactionMapResponse> orig_callback) {
        if (debug.val) LOG.debug("Trying to intialize TransactionMapWrapperCallback for " + this);
        assert (this.mapWrapper_callback.isInitialized() == false);
        this.mapWrapper_callback.init(this, orig_callback);
    }
   
    public void initTransactionReduceWrapperCallback(RpcCallback<TransactionReduceResponse> orig_callback) {
        if (debug.val) LOG.debug("Trying to initialize TransactionReduceWrapperCallback for " + this);
        //assert (this.reduceWrapper_callback.isInitialized() == false);
        this.reduceWrapper_callback.init(this, orig_callback);
    }

    /**
     * Get the TransactionCleanupCallback for this txn.
     */
    public RemoteFinishCallback getCleanupCallback() {
        // TODO(xin): This should return null if this handle is located at
        //            the txn's basePartition HStoreSite
        if (this.hstore_site.isLocalPartition(base_partition)) return null;
       
        assert(this.cleanup_callback.isInitialized()) :
            String.format("Trying to grab the %s for %s before it has been initialized",
                          this.cleanup_callback.getClass().getSimpleName(), this);
        return (this.cleanup_callback);
    }

    @Override
    public String toStringImpl() {
        return String.format("%s-%s #%d/%d", this.getProcedure().getName(),
                                             (this.getState() == null ? "null" : this.getState().toString()),
                                             this.txn_id, this.base_partition);
    }


    @Override
    public void initRound(int partition, long undoToken) {
        throw new RuntimeException("initRound should not be invoked on " + this.getClass());
    }

    @Override
    public void startRound(int partition) {
        throw new RuntimeException("startRound should not be invoked on " + this.getClass());
    }

    @Override
    public void finishRound(int partition) {
        throw new RuntimeException("finishRound should not be invoked on " + this.getClass());
    }
   
    public VoltTable getMapOutputByPartition( int partition ) {
        if (debug.val) LOG.debug("Trying to getMapOutputByPartition: [ " + partition + " ]");
        return this.mapOutput[partition];
    }
   
    public VoltTable getReduceInputByPartition ( int partition ) {
        if (debug.val) LOG.debug("Trying to getReduceInputByPartition: [ " + partition + " ]");
        return this.reduceInput[partition];
        //return this.reduceInput[partition];
    }
   
    public VoltTable getReduceOutputByPartition ( int partition ) {
        if (debug.val) LOG.debug("Trying to getReduceOutputByPartition: [ " + partition + " ]");
        return this.reduceOutput[partition];
        //return this.reduceOutput[partition];
    }

    /**
     * Reset variables in sub transactions to allow for re-execution.
     */
  public void resetTransaction() {
    for (LocalTransaction local_txn : this.local_txns) {
      local_txn.resetControlCodeExecuted();
      local_txn.resetClientResponse();
    }
  }
   
}
TOP

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

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.