Package edu.brown.hstore.callbacks

Source Code of edu.brown.hstore.callbacks.LocalPrepareCallback

package edu.brown.hstore.callbacks;

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

import org.apache.log4j.Logger;
import org.voltdb.ClientResponseImpl;

import com.google.protobuf.RpcCallback;

import edu.brown.hstore.HStoreSite;
import edu.brown.hstore.Hstoreservice.Status;
import edu.brown.hstore.Hstoreservice.TransactionPrepareResponse;
import edu.brown.hstore.txns.LocalTransaction;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.utils.PartitionSet;

/**
* This callback is invoked at the base partition once the txn gets all of
* the 2PC:PREPARE acknowledgments. This is where we will invoke the HStoreSite
* to send the ClientResponse back to the client.
* @author pavlo
*/
public class LocalPrepareCallback extends PartitionCountingCallback<LocalTransaction> implements RpcCallback<TransactionPrepareResponse> {
    private static final Logger LOG = Logger.getLogger(LocalPrepareCallback.class);
    private static final LoggerBoolean debug = new LoggerBoolean();
    static {
        LoggerUtil.attachObserver(LOG, debug);
    }
   
    private final List<TransactionPrepareResponse> responses = new ArrayList<TransactionPrepareResponse>();
   
    /**
     * Constructor
     * @param hstore_site
     */
    public LocalPrepareCallback(HStoreSite hstore_site) {
        super(hstore_site);
    }
   
    public void init(LocalTransaction ts, PartitionSet partitions) {
        this.responses.clear();
        super.init(ts, partitions);
    }

    // ----------------------------------------------------------------------------
    // CALLBACK METHODS
    // ----------------------------------------------------------------------------
   
    @Override
    protected void unblockCallback() {
        if (debug.val)
            LOG.debug(String.format("%s - Unblocking callback and sending back ClientResponse", this.ts));
        if (hstore_conf.site.txn_profiling && this.ts.profiler != null) {
            if (debug.val) LOG.debug(ts + " - TransactionProfiler.stopPostPrepare() / " + Status.OK);
            this.ts.profiler.stopPostPrepare();
            this.ts.profiler.startPostFinish();
        }

        // Everybody returned ok, so we'll tell them to all commit right now
        // so that they can start executing other things
        this.finishTransaction(Status.OK);
       
        // At this point all of our HStoreSites came back with an OK on the 2PC PREPARE
        // So that means we can send back the result to the client and then
        // send the 2PC COMMIT message to all of our friends.
        // We want to do this first because the transaction state could get
        // cleaned-up right away when we call HStoreCoordinator.transactionFinish()
        ClientResponseImpl cresponse = this.ts.getClientResponse();
        assert(cresponse.isInitialized()) :
            "Trying to send back ClientResponse for " + ts + " before it was set!";
        this.hstore_site.responseSend(this.ts, cresponse);
    }
   
    @Override
    protected void abortCallback(int partition, Status status) {
        if (debug.val)
            LOG.debug(String.format("%s - Aborting callback [status=%s]", this.ts, status));
        if (hstore_conf.site.txn_profiling && this.ts.profiler != null) {
            if (debug.val)
                LOG.debug(ts + " - TransactionProfiler.stopPostPrepare() / " + status);
            this.ts.profiler.stopPostPrepare();
            this.ts.profiler.startPostFinish();
        }
       
        // We don't care whether our transaction was rejected or not because we
        // know that we still need to call TransactionFinish, which will delete
        // the final transaction state
        if (status == Status.ABORT_RESTART || status == Status.ABORT_SPECULATIVE) {
            hstore_site.getTransactionQueueManager().restartTransaction(this.ts, status);
        }
        // Change the response's status and send back the result to the client
        else {
            ClientResponseImpl cresponse = this.ts.getClientResponse();
            cresponse.setStatus(status);
            if (debug.val)
                LOG.debug(String.format("%s - Sending back %s %s",
                          this.ts, status, cresponse.getClass().getSimpleName()));
            this.hstore_site.responseSend(this.ts, cresponse);
        }
    }
   
    // ----------------------------------------------------------------------------
    // RPC CALLBACK
    // ----------------------------------------------------------------------------
   
    @Override
    public void run(TransactionPrepareResponse response) {
        if (debug.val)
            LOG.debug(String.format("Got %s with %d partitions for %s",
                      response.getClass().getSimpleName(),
                      response.getPartitionsCount(),
                      this.ts));
        assert(this.ts != null) :
            String.format("Missing LocalTransaction handle for txn #%d [status=%s]",
                          response.getTransactionId(), response.getStatus());
        assert(this.ts.getTransactionId().longValue() == response.getTransactionId()) :
            String.format("Unexpected %s for a different transaction %s != #%d",
                          response.getClass().getSimpleName(), this.ts, response.getTransactionId());
       
        // If any TransactionPrepareResponse comes back with anything but an OK,
        // then the we need to abort the transaction immediately
        // TODO: Instead of OK, we should have different status types for what the
        //       remote partition did. It should be PREPARE_OK or PREPARE_COMMIT
        //       If it's a PREPARE_COMMIT then we know that we don't need to send
        //       a COMMIT message to it in the next round.
        this.responses.add(response);
        if (response.getStatus() != Status.OK) {
            boolean first = true;
            for (int partition : response.getPartitionsList()) {
                if (first) {
                    this.abort(partition, response.getStatus());
                    first = false;
                } else {
                    this.decrementCounter(partition);
                }
            } // FOR
        } else {
            for (Integer partition : response.getPartitionsList()) {
                this.run(partition.intValue());
            } // FOR
        }
    }
   
} // END CLASS
TOP

Related Classes of edu.brown.hstore.callbacks.LocalPrepareCallback

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.