@Override public void remoteHandler( RpcController controller, TransactionMapRequest request, RpcCallback<TransactionMapResponse> callback) { assert (request.hasTransactionId()) : "Got " + request.getClass().getSimpleName() + " without a txn id!"; Long txn_id = Long.valueOf(request.getTransactionId()); if (debug.val) LOG.debug(String.format("Got %s for txn #%d", request.getClass().getSimpleName(), txn_id)); // The mr_ts handle will be null if this HStoreSite is not where the // base partition for the original MRTransaction MapReduceTransaction mr_ts = hstore_site.getTransaction(txn_id); if (mr_ts == null) { mr_ts = hstore_site .getTransactionInitializer() .createMapReduceTransaction( txn_id, EstTime.currentTimeMillis(), request.getClientHandle(), request.getBasePartition(), request.getProcedureId(), request.getParams().asReadOnlyByteBuffer()); } assert (mr_ts.isMapPhase()); mr_ts.initTransactionMapWrapperCallback(callback); /* * Here we would like to start MapReduce Transaction on the remote partition except the base partition of it. * This is to avoid the double invoke for remote task. * */ for (int partition : hstore_site.getLocalPartitionIds()) { if (partition != mr_ts.getBasePartition()) { LocalTransaction ts = mr_ts.getLocalTransaction(partition); hstore_site.transactionStart(ts); } } // FOR }
/** @return */ public final VoltTable run(Object params[]) { assert (this.hstore_site != null) : "error in VoltMapReduceProcedure...for hstore_site.........."; VoltTable result = null; // The MapReduceTransaction handle will have all the key information we need about this txn long txn_id = this.getTransactionId(); this.mr_ts = this.hstore_site.getTransaction(txn_id); assert (mr_ts != null) : "Unexpected null MapReduceTransaction handle for " + this.m_localTxnState; // If this invocation is at the txn's base partition, then it is // responsible for sending out the coordination messages to the other partitions boolean is_local = (this.partitionId == mr_ts.getBasePartition()); if (mr_ts.isMapPhase()) { // If this is the base partition, then we'll send the out the MAP // initialization requests to all of the partitions if (is_local) { // Send out network messages to all other partitions to tell them to // execute the MAP phase of this job if (debug.get()) LOG.debug("<VoltMapReduceProcedure.run> is executing ..<Map>...local!!!....\n"); this.executor .getHStoreCoordinator() .transactionMap(mr_ts, mr_ts.getTransactionMapCallback()); } this.map_output = mr_ts.getMapOutputByPartition(this.partitionId); assert (this.map_output != null); if (debug.get()) LOG.debug("<VoltMapReduceProcedure.run> is executing ..<MAP>..\n"); // Execute the map voltQueueSQL(mapInputQuery, params); VoltTable mapResult[] = voltExecuteSQLForceSinglePartition(); assert (mapResult.length == 1); // Check whether the HStoreConf flag for locking the entire cluster // is true. If it is, then we have to tell the queue manager that we're done. // MapReduceTransaction should finish forever... if (this.hstore_conf.site.mr_map_blocking) { hstore_site.getTransactionQueueManager().lockFinished(txn_id, Status.OK, this.partitionId); } if (debug.get()) LOG.debug( String.format( "MAP: About to process %d records for %s on partition %d", mapResult[0].getRowCount(), this.m_localTxnState, this.partitionId)); if (debug.get()) LOG.debug( String.format("<MapInputTable> Partition:%d\n %s", this.partitionId, mapResult[0])); while (mapResult[0].advanceRow()) { this.map(mapResult[0].getRow()); } // WHILE if (debug.get()) LOG.debug( String.format( "MAP: %s generated %d results on partition %d", this.m_localTxnState, this.map_output.getRowCount(), this.partitionId)); if (debug.get()) LOG.debug( String.format("<MapOutputTable> Partition:%d\n %s", this.partitionId, this.map_output)); result = mr_ts.getMapOutputByPartition(this.partitionId); // Always invoke the TransactionMapWrapperCallback to let somebody know that // we finished the MAP phase at this partition TransactionMapWrapperCallback callback = mr_ts.getTransactionMapWrapperCallback(); assert (callback != null) : "Unexpected null callback for " + mr_ts; assert (callback.isInitialized()) : "Unexpected uninitalized callback for " + mr_ts; callback.run(this.partitionId); } else if (mr_ts.isReducePhase()) { // If this is the local/base partition, send out the start REDUCE message if (is_local) { if (debug.get()) LOG.debug("<VoltMapReduceProcedure.run> is executing ..<Reduce>...local!!!....\n"); // Send out network messages to all other partitions to tell them to execute the Reduce // phase of this job this.executor .getHStoreCoordinator() .transactionReduce(mr_ts, mr_ts.getTransactionReduceCallback()); } this.reduce_input = null; // this.reduce_input = mr_ts.getReduceInputByPartition(this.partitionId); assert (this.reduce_input != null); if (debug.get()) LOG.debug( "__FILE__:__LINE__ " + String.format( "TXN: %s, [Stage] \n<VoltMapReduceProcedure.run> is executing <Reduce>..", mr_ts)); if (debug.get()) LOG.debug( String.format( "<ReduceInputTable> Partition:%d\n %s", this.partitionId, this.reduce_input)); // Sort the the MAP_OUTPUT table // Build an "smart" iterator that loops through the MAP_OUTPUT table key-by-key VoltTable sorted = VoltTableUtil.sort(this.reduce_input, Pair.of(0, SortDirectionType.ASC)); // VoltTable sorted = VoltTableUtil.sort(mr_ts.getReduceInputByPartition(this.partitionId), // Pair.of(0, SortDirectionType.ASC)); assert (sorted != null); if (debug.get()) LOG.debug( String.format("<Sorted_ReduceInputTable> Partition:%d\n %s", this.partitionId, sorted)); this.reduce_output = mr_ts.getReduceOutputByPartition(this.partitionId); assert (this.reduce_output != null); // Make a Hstore.PartitionResult ReduceInputIterator<K> rows = new ReduceInputIterator<K>(sorted); // Loop over that iterator and call runReduce if (debug.get()) LOG.debug( String.format( "REDUCE: About to process %d records for %s on partition %d", sorted.getRowCount(), this.m_localTxnState, this.partitionId)); while (rows.hasNext()) { K key = rows.getKey(); this.reduce(key, rows); } if (debug.get()) LOG.debug( String.format( "<ReduceOutputTable> Partition:%d\n %s", this.partitionId, this.reduce_output)); // Loop over that iterator and call runReduce if (debug.get()) LOG.debug( String.format( "REDUCE: %s generated %d results on partition %d", this.m_localTxnState, this.reduce_output.getRowCount(), this.partitionId)); ByteString reduceOutData = null; try { ByteBuffer b = ByteBuffer.wrap(FastSerializer.serialize(reduce_output)); reduceOutData = ByteString.copyFrom(b.array()); } catch (Exception ex) { throw new RuntimeException( String.format( "Unexpected error when serializing %s reduceOutput data for partition %d", mr_ts, this.partitionId), ex); } ReduceResult.Builder builder = ReduceResult.newBuilder() .setData(reduceOutData) .setPartitionId(this.partitionId) .setStatus(Status.OK); TransactionReduceWrapperCallback callback = mr_ts.getTransactionReduceWrapperCallback(); assert (callback != null) : "Unexpected null TransactionReduceWrapperCallback for " + mr_ts; assert (callback.isInitialized()) : "Unexpected uninitalized TransactionReduceWrapperCallback for " + mr_ts; callback.run(builder.build()); } return (result); }