com.splicemachine.si.data.hbase.coprocessor.TxnLifecycleEndpoint.java Source code

Java tutorial

Introduction

Here is the source code for com.splicemachine.si.data.hbase.coprocessor.TxnLifecycleEndpoint.java

Source

/*
 * Copyright (c) 2012 - 2017 Splice Machine, Inc.
 *
 * This file is part of Splice Machine.
 * Splice Machine is free software: you can redistribute it and/or modify it under the terms of the
 * GNU Affero General Public License as published by the Free Software Foundation, either
 * version 3, or (at your option) any later version.
 * Splice Machine is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 * You should have received a copy of the GNU Affero General Public License along with Splice Machine.
 * If not, see <http://www.gnu.org/licenses/>.
 */

package com.splicemachine.si.data.hbase.coprocessor;

import java.io.IOException;

import com.google.common.primitives.Longs;
import com.google.protobuf.RpcCallback;
import com.google.protobuf.RpcController;
import com.google.protobuf.Service;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.hadoop.hbase.Coprocessor;
import org.apache.hadoop.hbase.CoprocessorEnvironment;
import org.apache.hadoop.hbase.coprocessor.CoprocessorService;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.protobuf.ResponseConverter;
import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.log4j.Logger;

import com.splicemachine.access.api.SConfiguration;
import com.splicemachine.concurrent.CountedReference;
import com.splicemachine.concurrent.SystemClock;
import com.splicemachine.constants.EnvUtils;
import com.splicemachine.hbase.ZkUtils;
import com.splicemachine.si.api.txn.lifecycle.TxnLifecycleStore;
import com.splicemachine.si.api.txn.lifecycle.TxnPartition;
import com.splicemachine.si.coprocessor.TxnMessage;
import com.splicemachine.si.impl.data.StripedTxnLifecycleStore;
import com.splicemachine.si.impl.driver.SIDriver;
import com.splicemachine.si.impl.region.RegionServerControl;
import com.splicemachine.si.impl.region.RegionTxnStore;
import com.splicemachine.si.impl.region.TransactionResolver;
import com.splicemachine.timestamp.api.TimestampSource;
import com.splicemachine.utils.Source;
import com.splicemachine.utils.SpliceLogUtils;
import org.spark_project.guava.base.Supplier;

/**
 * @author Scott Fines
 *         Date: 6/19/14
 */
public class TxnLifecycleEndpoint extends TxnMessage.TxnLifecycleService
        implements CoprocessorService, Coprocessor {
    private static final Logger LOG = Logger.getLogger(TxnLifecycleEndpoint.class);

    private TxnLifecycleStore lifecycleStore;
    private volatile boolean isTxnTable = false;

    public static final CountedReference<TransactionResolver> resolverRef = new CountedReference<>(
            new Supplier<TransactionResolver>() {
                @Override
                public TransactionResolver get() {
                    return new TransactionResolver(SIDriver.driver().getTxnSupplier(), 2, 128);
                }
            }, new CountedReference.ShutdownAction<TransactionResolver>() {
                @Override
                public void shutdown(TransactionResolver instance) {
                    instance.shutdown();
                }
            });

    @Override
    public void start(CoprocessorEnvironment env) throws IOException {
        RegionCoprocessorEnvironment rce = (RegionCoprocessorEnvironment) env;
        HRegion region = (HRegion) rce.getRegion();
        HBaseSIEnvironment siEnv = HBaseSIEnvironment.loadEnvironment(new SystemClock(),
                ZkUtils.getRecoverableZooKeeper());
        SConfiguration configuration = siEnv.configuration();
        TableType table = EnvUtils.getTableType(configuration, rce);
        if (table.equals(TableType.TRANSACTION_TABLE)) {
            TransactionResolver resolver = resolverRef.get();
            SIDriver driver = siEnv.getSIDriver();
            assert driver != null : "SIDriver Cannot be null";
            long txnKeepAliveTimeout = configuration.getTransactionTimeout();
            @SuppressWarnings("unchecked")
            TxnPartition regionStore = new RegionTxnStore(region, driver.getTxnSupplier(), resolver,
                    txnKeepAliveTimeout, new SystemClock());
            TimestampSource timestampSource = driver.getTimestampSource();
            int txnLockStrips = configuration.getTransactionLockStripes();
            lifecycleStore = new StripedTxnLifecycleStore(txnLockStrips, regionStore,
                    new RegionServerControl(region, rce.getRegionServerServices()), timestampSource);
            isTxnTable = true;
        }
    }

    @Override
    public void stop(CoprocessorEnvironment env) {
        SpliceLogUtils.info(LOG, "Shutting down TxnLifecycleEndpoint");
        if (isTxnTable) {
            resolverRef.release(true);
        }
    }

    @Override
    public Service getService() {
        SpliceLogUtils.trace(LOG, "Getting the TxnLifecycle Service");
        return this;
    }

    @Override
    public void beginTransaction(RpcController controller, TxnMessage.TxnInfo request,
            RpcCallback<TxnMessage.VoidResponse> done) {
        try {
            lifecycleStore.beginTransaction(request);
            done.run(TxnMessage.VoidResponse.getDefaultInstance());
        } catch (IOException ioe) {
            ResponseConverter.setControllerException(controller, ioe);
        }
    }

    @Override
    public void elevateTransaction(RpcController controller, TxnMessage.ElevateRequest request,
            RpcCallback<TxnMessage.VoidResponse> done) {
        if (request.getNewDestinationTable() == null) {
            LOG.warn(
                    "Attempting to elevate a transaction with no destination table. This is probably a waste of a network call");
            return;
        }
        try {
            lifecycleStore.elevateTransaction(request.getTxnId(), request.getNewDestinationTable().toByteArray());
            done.run(TxnMessage.VoidResponse.getDefaultInstance());
        } catch (IOException ioe) {
            ResponseConverter.setControllerException(controller, ioe);
        }
    }

    @Override
    public void beginChildTransaction(RpcController controller, TxnMessage.CreateChildRequest request,
            RpcCallback<TxnMessage.Txn> done) {

    }

    @Override
    @SuppressFBWarnings(value = "SF_SWITCH_NO_DEFAULT", justification = "Intentional")
    public void lifecycleAction(RpcController controller, TxnMessage.TxnLifecycleMessage request,
            RpcCallback<TxnMessage.ActionResponse> done) {
        try {
            TxnMessage.ActionResponse response = null;
            switch (request.getAction()) {
            case COMMIT:
                response = TxnMessage.ActionResponse.newBuilder().setCommitTs(commit(request.getTxnId())).build();
                break;
            case TIMEOUT:
            case ROLLBACk:
                rollback(request.getTxnId());
                response = TxnMessage.ActionResponse.getDefaultInstance();
                break;
            case KEEPALIVE:
                boolean b = keepAlive(request.getTxnId());
                response = TxnMessage.ActionResponse.newBuilder().setContinue(b).build();
                break;
            case ROLLBACK_SUBTRANSACTIONS:
                long[] ids = Longs.toArray(request.getRolledbackSubTxnsList());
                rollbackSubtransactions(request.getTxnId(), ids);
                response = TxnMessage.ActionResponse.getDefaultInstance();
                break;
            }
            done.run(response);
        } catch (IOException ioe) {
            ResponseConverter.setControllerException(controller, ioe);
        }
    }

    @Override
    public void getTransaction(RpcController controller, TxnMessage.TxnRequest request,
            RpcCallback<TxnMessage.Txn> done) {
        try {
            long txnId = request.getTxnId();
            TxnMessage.Txn transaction = lifecycleStore.getTransaction(txnId);
            done.run(transaction);
        } catch (IOException ioe) {
            ResponseConverter.setControllerException(controller, ioe);
        }
    }

    @Override
    public void getActiveTransactionIds(RpcController controller, TxnMessage.ActiveTxnRequest request,
            RpcCallback<TxnMessage.ActiveTxnIdResponse> done) {
        long endTxnId = request.getEndTxnId();
        long startTxnId = request.getStartTxnId();
        try {
            byte[] destTables = null;
            if (request.hasDestinationTables())
                destTables = request.getDestinationTables().toByteArray();
            long[] activeTxnIds = lifecycleStore.getActiveTransactionIds(destTables, startTxnId, endTxnId);
            TxnMessage.ActiveTxnIdResponse.Builder response = TxnMessage.ActiveTxnIdResponse.newBuilder();
            //noinspection ForLoopReplaceableByForEach
            for (int i = 0; i < activeTxnIds.length; i++) {
                response.addActiveTxnIds(activeTxnIds[i]);
            }
            done.run(response.build());
        } catch (IOException e) {
            ResponseConverter.setControllerException(controller, e);
        }
    }

    @Override
    public void getActiveTransactions(RpcController controller, TxnMessage.ActiveTxnRequest request,
            RpcCallback<TxnMessage.ActiveTxnResponse> done) {
        long endTxnId = request.getEndTxnId();
        long startTxnId = request.getStartTxnId();
        try {
            byte[] destTables = null;
            if (request.hasDestinationTables())
                destTables = request.getDestinationTables().toByteArray();
            Source<TxnMessage.Txn> activeTxns = lifecycleStore.getActiveTransactions(destTables, startTxnId,
                    endTxnId);
            TxnMessage.ActiveTxnResponse.Builder response = TxnMessage.ActiveTxnResponse.newBuilder();
            while (activeTxns.hasNext()) {
                response.addTxns(activeTxns.next());
            }
            done.run(response.build());
        } catch (IOException e) {
            ResponseConverter.setControllerException(controller, e);
        }

    }

    public long commit(long txnId) throws IOException {
        return lifecycleStore.commitTransaction(txnId);
    }

    public void rollbackSubtransactions(long txnId, long[] subIds) throws IOException {
        lifecycleStore.rollbackSubtransactions(txnId, subIds);
    }

    public void rollback(long txnId) throws IOException {
        lifecycleStore.rollbackTransaction(txnId);
    }

    public boolean keepAlive(long txnId) throws IOException {
        return lifecycleStore.keepAlive(txnId);
    }

    @Override
    public void rollbackTransactionsAfter(RpcController controller, TxnMessage.TxnRequest request,
            RpcCallback<TxnMessage.VoidResponse> done) {

        try {
            lifecycleStore.rollbackTransactionsAfter(request.getTxnId());
            done.run(TxnMessage.VoidResponse.getDefaultInstance());
        } catch (IOException ioe) {
            ResponseConverter.setControllerException(controller, ioe);
        }
    }
}