org.apache.hadoop.hbase.coprocessor.transactional.SsccRegionEndpoint.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hbase.coprocessor.transactional.SsccRegionEndpoint.java

Source

// @@@ START COPYRIGHT @@@
//
// (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
// @@@ END COPYRIGHT @@@

package org.apache.hadoop.hbase.coprocessor.transactional;

import java.io.IOException;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.Coprocessor;
import org.apache.hadoop.hbase.CoprocessorEnvironment;
import org.apache.hadoop.hbase.coprocessor.ColumnInterpreter;
import org.apache.hadoop.hbase.coprocessor.CoprocessorException;
import org.apache.hadoop.hbase.coprocessor.CoprocessorService;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;

import java.io.*;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.StringBuilder;
import java.lang.StringBuilder;
import java.lang.Thread.UncaughtExceptionHandler;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableSet;
import java.util.NavigableMap;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.UUID;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Durability;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Increment;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.client.ScannerTimeoutException;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.transactional.UnknownTransactionException;

import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.filter.FilterBase;
import org.apache.hadoop.hbase.filter.FilterList;
import org.apache.hadoop.hbase.KeyValueUtil;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.KeyValue.Type;
import org.apache.hadoop.hbase.Coprocessor;
import org.apache.hadoop.hbase.CoprocessorEnvironment;
import org.apache.hadoop.hbase.coprocessor.CoprocessorException;
import org.apache.hadoop.hbase.coprocessor.CoprocessorService;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.coprocessor.RegionObserver;
import org.apache.hadoop.hbase.exceptions.OutOfOrderScannerNextException;
import org.apache.hadoop.hbase.filter.FilterBase;
import org.apache.hadoop.hbase.coprocessor.CoprocessorService;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.coprocessor.RegionObserver;
import org.apache.hadoop.hbase.filter.FilterList;
import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HBaseInterfaceAudience;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.Tag;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.regionserver.RegionServerServices;
import org.apache.hadoop.hbase.Stoppable;
import org.apache.hadoop.hbase.NotServingRegionException;
import org.apache.hadoop.hbase.UnknownScannerException;
import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.regionserver.KeyValueScanner;
import org.apache.hadoop.hbase.regionserver.LeaseException;
import org.apache.hadoop.hbase.regionserver.LeaseListener;
import org.apache.hadoop.hbase.regionserver.Leases;
import org.apache.hadoop.hbase.regionserver.Leases.LeaseStillHeldException;
import org.apache.hadoop.hbase.regionserver.MultiVersionConsistencyControl;
import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost;
import org.apache.hadoop.hbase.regionserver.RegionScanner;
import org.apache.hadoop.hbase.regionserver.WrongRegionException;
import org.apache.hadoop.hbase.regionserver.wal.HLog;
import org.apache.hadoop.hbase.regionserver.wal.HLogKey;
import org.apache.hadoop.hbase.regionserver.wal.HLogUtil;
import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
import org.apache.hadoop.hbase.regionserver.transactional.CleanOldTransactionsChore;
import org.apache.hadoop.hbase.regionserver.transactional.SsccTransactionState;
import org.apache.hadoop.hbase.regionserver.transactional.IdTm;
import org.apache.hadoop.hbase.regionserver.transactional.IdTmException;
import org.apache.hadoop.hbase.regionserver.transactional.IdTmId;
import org.apache.hadoop.hbase.regionserver.transactional.TransactionalRegion;
import org.apache.hadoop.hbase.regionserver.transactional.TransactionalRegionScannerHolder;
import org.apache.hadoop.hbase.regionserver.transactional.TransactionState.Status;
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.FSUtils;
import org.apache.hadoop.hbase.util.Threads;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.protobuf.ResponseConverter;
import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto;
import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.MutationType;
import org.apache.hadoop.hbase.coprocessor.transactional.TrxRegionObserver;

// Sscc imports
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccRegionService;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccBeginTransactionRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccBeginTransactionResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCommitRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCommitResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccAbortTransactionRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccAbortTransactionResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCommitRequestRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCommitRequestResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCommitIfPossibleRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCommitIfPossibleResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccGetTransactionalRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccGetTransactionalResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccPerformScanRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccPerformScanResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccOpenScannerRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccOpenScannerResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccPutTransactionalRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccPutTransactionalResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccDeleteTransactionalRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccDeleteTransactionalResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCloseScannerRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCloseScannerResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCheckAndDeleteRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCheckAndDeleteResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCheckAndPutRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCheckAndPutResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccDeleteMultipleTransactionalRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccDeleteMultipleTransactionalResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccPutMultipleTransactionalRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccPutMultipleTransactionalResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccRecoveryRequestRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccRecoveryRequestResponse;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccTransactionalAggregateRequest;
import org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccTransactionalAggregateResponse;

import org.apache.hadoop.hbase.client.DtmConst;
import org.apache.hadoop.hbase.client.SsccConst;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
import org.apache.hadoop.hbase.zookeeper.ZKUtil;
import org.apache.zookeeper.KeeperException;

import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import com.google.protobuf.RpcCallback;
import com.google.protobuf.RpcController;
import com.google.protobuf.Service;
import com.google.protobuf.ServiceException;

@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC)
@InterfaceStability.Evolving
public class SsccRegionEndpoint<T, S, P extends Message, Q extends Message, R extends Message>
        extends SsccRegionService implements CoprocessorService, Coprocessor {

    private static final Log LOG = LogFactory.getLog(SsccRegionEndpoint.class);

    private RegionCoprocessorEnvironment env;

    ConcurrentHashMap<String, Object> transactionsByIdTestz = null;

    // Collection of active transactions (PENDING) keyed by id.
    protected ConcurrentHashMap<String, SsccTransactionState> transactionsById = new ConcurrentHashMap<String, SsccTransactionState>();

    // Map of recent transactions that are COMMIT_PENDING or COMMITED keyed by
    // their sequence number
    private SortedMap<Long, SsccTransactionState> commitedTransactionsBySequenceNumber = Collections
            .synchronizedSortedMap(new TreeMap<Long, SsccTransactionState>());

    // Collection of transactions that are COMMIT_PENDING
    private Set<SsccTransactionState> commitPendingTransactions = Collections
            .synchronizedSet(new HashSet<SsccTransactionState>());

    // an in-doubt transaction list during recovery WALEdit replay
    private Map<Long, WALEdit> indoubtTransactionsById = new TreeMap<Long, WALEdit>();

    // an in-doubt transaction list count by TM id
    private Map<Integer, Integer> indoubtTransactionsCountByTmid = new TreeMap<Integer, Integer>();

    // Concurrent map for transactional region scanner holders
    // Protected by synchronized methods
    final ConcurrentHashMap<Long, TransactionalRegionScannerHolder> scanners = new ConcurrentHashMap<Long, TransactionalRegionScannerHolder>();

    // Atomic values to manage region scanners
    private AtomicLong performScannerId = new AtomicLong(0);
    //  private AtomicInteger nextSequenceId = new AtomicInteger(0);

    private Object commitCheckLock = new Object();
    private Object recoveryCheckLock = new Object();
    private Object editReplay = new Object();
    private Object stoppableLock = new Object();
    private int reconstructIndoubts = 0;
    //temporary THLog getSequenceNumber() replacement
    private AtomicLong nextLogSequenceId = new AtomicLong(0);
    private final int oldTransactionFlushTrigger = 0;
    private final Boolean splitDelayEnabled = false;
    private final Boolean doWALHlog = false;
    static Leases transactionLeases = null;
    //  CleanOldTransactionsChore cleanOldTransactionsThread;
    //  CompleteTransactionsChore completeTransactionsThread;
    static Stoppable stoppable = new StoppableImplementation();
    private int cleanTimer = 5000; // Five minutes
    private int regionState = 0;
    private Path recoveryTrxPath = null;
    private int cleanAT = 0;
    private long[] commitCheckTimes = new long[50];
    private long[] hasConflictTimes = new long[50];
    private long[] putBySequenceTimes = new long[50];
    private long[] writeToLogTimes = new long[50];

    private AtomicInteger timeIndex = new AtomicInteger(0);
    private AtomicInteger totalCommits = new AtomicInteger(0);
    private AtomicInteger writeToLogOperations = new AtomicInteger(0);
    private AtomicInteger putBySequenceOperations = new AtomicInteger(0);
    private long totalCommitCheckTime = 0;
    private long totalConflictTime = 0;
    private long totalPutTime = 0;
    private long totalWriteToLogTime = 0;
    private long minCommitCheckTime = 1000000000;
    private long maxCommitCheckTime = 0;
    private double avgCommitCheckTime = 0;
    private long minConflictTime = 1000000000;
    private long maxConflictTime = 0;
    private double avgConflictTime = 0;
    private long minPutTime = 1000000000;
    private long maxPutTime = 0;
    private double avgPutTime = 0;
    private long minWriteToLogTime = 1000000000;
    private long maxWriteToLogTime = 0;
    private double avgWriteToLogTime = 0;

    private HRegionInfo regionInfo = null;
    private HRegion m_Region = null;
    private TransactionalRegion t_Region = null;
    private FileSystem fs = null;
    private RegionCoprocessorHost rch = null;
    private HLog tHLog = null;
    boolean closing = false;
    private boolean fullEditInCommit = true;
    private boolean configuredEarlyLogging = false;
    private static Object zkRecoveryCheckLock = new Object();
    private static ZooKeeperWatcher zkw1 = null;
    String lv_hostName;
    int lv_port;
    private static String zNodePath = "/hbase/Trafodion/recovery/";

    private static final int DEFAULT_LEASE_TIME = 7200 * 1000;
    private static final int LEASE_CHECK_FREQUENCY = 1000;
    private static final String SLEEP_CONF = "hbase.transaction.clean.sleep";
    private static final int DEFAULT_SLEEP = 60 * 1000;
    protected static int transactionLeaseTimeout = 0;
    private static int scannerLeaseTimeoutPeriod = 0;
    private static int scannerThreadWakeFrequency = 0;

    // Transaction state defines
    private static final int COMMIT_OK = 1;
    private static final int COMMIT_OK_READ_ONLY = 2;
    private static final int COMMIT_UNSUCCESSFUL = 3;
    private static final int COMMIT_CONFLICT = 5;

    // update return code defines
    private static final int STATEFUL_UPDATE_OK = 1;
    private static final int STATEFUL_UPDATE_CONFLICT = 2;
    private static final int STATELESS_UPDATE_OK = 3;
    private static final int STATELESS_UPDATE_CONFLICT = 5;

    private static final int CLOSE_WAIT_ON_COMMIT_PENDING = 1000;
    private static final int MAX_COMMIT_PENDING_WAITS = 10;
    private Thread ChoreThread = null;
    //private static Thread ScannerLeasesThread = null;
    private static Thread TransactionalLeasesThread = null;
    private static boolean editGenerated = false;

    private static final int COMMIT_REQUEST = 1;
    private static final int COMMIT = 2;
    private static final int ABORT = 3;
    private static final int CONTROL_POINT_COMMIT = 4;

    private Map<Long, Long> updateTsToStartId = new TreeMap<Long, Long>();
    private AtomicLong nextSsccSequenceId;

    private IdTm idServer;
    private static final int ID_TM_SERVER_TIMEOUT = 1000;

    // SsccRegionService methods
    @Override
    public void beginTransaction(RpcController controller, SsccBeginTransactionRequest request,
            RpcCallback<SsccBeginTransactionResponse> done) {
        SsccBeginTransactionResponse response = SsccBeginTransactionResponse.getDefaultInstance();

        long transId = request.getTransactionId();
        long startId = request.getStartId();

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: beginTransaction - id " + transId + ", regionName "
                    + regionInfo.getRegionNameAsString());

        Throwable t = null;
        java.lang.String name = ((com.google.protobuf.ByteString) request.getRegionName()).toStringUtf8();
        WrongRegionException wre = null;
        try {
            beginTransaction(transId, startId);
        } catch (Throwable e) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:beginTransaction threw exception after internal begin");
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  Caught exception " + e.getMessage() + ""
                        + stackTraceToString(e));
            t = e;
        }

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccBeginTransactionResponse.Builder SsccBeginTransactionResponseBuilder = SsccBeginTransactionResponse
                .newBuilder();

        SsccBeginTransactionResponseBuilder.setHasException(false);

        if (t != null) {
            SsccBeginTransactionResponseBuilder.setHasException(true);
            SsccBeginTransactionResponseBuilder.setException(t.toString());
        }

        if (wre != null) {
            SsccBeginTransactionResponseBuilder.setHasException(true);
            SsccBeginTransactionResponseBuilder.setException(wre.toString());
        }

        SsccBeginTransactionResponse bresponse = SsccBeginTransactionResponseBuilder.build();

        done.run(bresponse);
    }

    /**
     * Begin a transaction
     * @param longtransactionId
     * @throws IOException
     */

    public void beginTransaction(final long transactionId, final long startId) throws IOException {

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  beginTransaction -- ENTRY txId: " + transactionId
                    + " startId: " + startId);
        checkClosing(transactionId);

        // TBD until integration with recovery
        if (reconstructIndoubts == 0) {
            if (LOG.isTraceEnabled())
                LOG.trace(
                        "SsccRegionEndpoint coprocessor:  RECOV beginTransaction -- ENTRY txId: " + transactionId);
            //       try {
            constructIndoubtTransactions();
            //       }
            //       catch (IdTmException e){
            //          LOG.error("SsccRegionEndpoint coprocessor:  RECOV beginTransaction exception" + e);
            //          throw new IOException("SsccRegionEndpoint coprocessor:  RECOV beginTransaction " + e);
            //       }
            //       catch (Exception e2) {
            //          LOG.error("SsccRegionEndpoint coprocessor:  RECOV beginTransaction exception" + e2);
            //          throw new IOException("SsccRegionEndpoint coprocessor:  RECOV beginTransaction exception " + e2);
            //       }
        }
        if (regionState != 2) {
            if (LOG.isTraceEnabled())
                LOG.trace(
                        "SsccRegionEndpoint coprocessor: Trafodion Recovery: RECOVERY WARN beginTransaction while the region is still in recovering state "
                                + regionState);
        }

        String key = getTransactionalUniqueId(transactionId);
        SsccTransactionState state;
        synchronized (transactionsById) {
            if (LOG.isTraceEnabled())
                LOG.trace(
                        "SsccRegionEndpoint coprocessor:  beginTransaction -- creating new SsccTransactionState without coprocessorHost txId: "
                                + transactionId);

            state = new SsccTransactionState(transactionId, nextLogSequenceId.getAndIncrement(), nextLogSequenceId,
                    m_Region.getRegionInfo(), m_Region.getTableDesc(), tHLog, configuredEarlyLogging, startId);
            //                                nextSsccSequenceId.getAndIncrement());

            state.setStartSequenceNumber(state.getStartId());

            //    List<TransactionState> commitPendingCopy =
            //        new ArrayList<SsccTransactionState>(commitPendingTransactions);

            //    for (SsccTransactionState commitPending : commitPendingCopy) {
            //            state.addTransactionToCheck(commitPending);
            //    }

            transactionsById.put(key, state);

            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  beginTransaction - Adding transaction: ["
                        + transactionId + "] in region [" + m_Region.getRegionInfo().getRegionNameAsString() + "]"
                        + " to list");
        }

        try {
            transactionLeases.createLease(key, transactionLeaseTimeout,
                    new TransactionLeaseListener(transactionId));
        } catch (LeaseStillHeldException e) {
            LOG.error("SsccRegionEndpoint coprocessor:  beginTransaction - Lease still held for [" + transactionId
                    + "] in region [" + m_Region.getRegionInfo().getRegionNameAsString() + "]");
            throw new RuntimeException(e);
        }

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  beginTransaction -- EXIT txId: " + transactionId
                    + " transactionsById size: " + transactionsById.size() + " region ID: "
                    + this.regionInfo.getRegionId());
    }

    /**begin transaction if not yet
      * @param transactionId
      * @return true: begin; false: not necessary to begin
      * @throws IOException
     */
    private SsccTransactionState beginTransIfNotExist(final long transactionId, final long startId)
            throws IOException {

        if (LOG.isTraceEnabled())
            LOG.trace("Enter SsccRegionEndpoint coprocessor: beginTransIfNotExist, txid: " + transactionId
                    + " startId: " + startId + " transactionsById size: " + transactionsById.size());

        String key = getTransactionalUniqueId(transactionId);
        synchronized (transactionsById) {
            SsccTransactionState state = transactionsById.get(key);
            if (state == null) {
                if (LOG.isTraceEnabled())
                    LOG.trace(
                            "SsccRegionEndpoint coprocessor:  Begin transaction in beginTransIfNotExist beginning the transaction internally as state was null");
                this.beginTransaction(transactionId, startId);
                state = transactionsById.get(key);
            }
            return state;
        }
    }

    /**
     * Gets the transaction state
     * @param long transactionId
     * @return SsccTransactionState
     * @throws UnknownTransactionException
     */
    protected SsccTransactionState getTransactionState(final long transactionId)
            throws UnknownTransactionException {
        SsccTransactionState state = null;
        boolean throwUTE = false;

        String key = getTransactionalUniqueId(transactionId);
        state = transactionsById.get(key);
        if (state == null) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: getTransactionState Unknown transaction: ["
                        + transactionId + "], throwing UnknownTransactionException");
            throwUTE = true;
        } else {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: getTransactionState Found transaction: [" + transactionId
                        + "]");

            try {
                transactionLeases.renewLease(key);
            } catch (LeaseException e) {
                if (LOG.isTraceEnabled())
                    LOG.trace(
                            "SsccRegionEndpoint coprocessor: getTransactionState renewLease failed will try to createLease for transaction: ["
                                    + transactionId + "]");
                try {
                    transactionLeases.createLease(key, transactionLeaseTimeout,
                            new TransactionLeaseListener(transactionId));
                } catch (LeaseStillHeldException lshe) {
                    if (LOG.isTraceEnabled())
                        LOG.trace(
                                "SsccRegionEndpoint coprocessor: getTransactionState renewLeasefollowed by createLease failed throwing original LeaseException for transaction: ["
                                        + transactionId + "]");
                    throw new RuntimeException(e);
                }
            }
        }

        if (throwUTE) {
            throw new UnknownTransactionException();
        }

        return state;
    }

    @Override
    public void commit(RpcController controller, SsccCommitRequest request, RpcCallback<SsccCommitResponse> done) {
        SsccCommitResponse response = SsccCommitResponse.getDefaultInstance();
        long transId = request.getTransactionId();
        long commitId = request.getCommitId();

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: commit - id " + transId + ", regionName "
                    + regionInfo.getRegionNameAsString());

        Throwable t = null;
        WrongRegionException wre = null;

        {
            // Process local memory
            try {
                commit(transId, commitId, request.getIgnoreUnknownTransactionException());
            } catch (Throwable e) {
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:commit threw exception after internal commit");
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:  Caught exception " + e.getMessage() + ""
                            + stackTraceToString(e));
                t = e;
            }
        }

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCommitResponse.Builder commitResponseBuilder = SsccCommitResponse
                .newBuilder();

        commitResponseBuilder.setHasException(false);

        if (t != null) {
            commitResponseBuilder.setHasException(true);
            commitResponseBuilder.setException(t.toString());
        }

        if (wre != null) {
            commitResponseBuilder.setHasException(true);
            commitResponseBuilder.setException(wre.toString());
        }

        SsccCommitResponse cresponse = commitResponseBuilder.build();

        done.run(cresponse);
    }

    @Override
    public void commitIfPossible(RpcController controller, SsccCommitIfPossibleRequest request,
            RpcCallback<SsccCommitIfPossibleResponse> done) {
        SsccCommitIfPossibleResponse response = SsccCommitIfPossibleResponse.getDefaultInstance();

        boolean reply = false;
        Throwable t = null;
        WrongRegionException wre = null;
        long transId = request.getTransactionId();

        {
            // Process local memory
            try {
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor: commitIfPossible - id " + transId + ", regionName, "
                            + regionInfo.getRegionNameAsString() + "calling internal commitIfPossible");
                reply = commitIfPossible(transId);
            } catch (Throwable e) {
                if (LOG.isTraceEnabled())
                    LOG.trace(
                            "SsccRegionEndpoint coprocessor:commitIfPossible threw exception after internal commitIfPossible");
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:  Caught exception " + e.getMessage() + ""
                            + stackTraceToString(e));
                t = e;
            }
        }

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCommitIfPossibleResponse.Builder commitIfPossibleResponseBuilder = SsccCommitIfPossibleResponse
                .newBuilder();

        commitIfPossibleResponseBuilder.setHasException(false);

        if (t != null) {
            commitIfPossibleResponseBuilder.setHasException(true);
            commitIfPossibleResponseBuilder.setException(t.toString());
        }

        if (wre != null) {
            commitIfPossibleResponseBuilder.setHasException(true);
            commitIfPossibleResponseBuilder.setException(wre.toString());
        }

        commitIfPossibleResponseBuilder.setWasSuccessful(reply);
        SsccCommitIfPossibleResponse cresponse = commitIfPossibleResponseBuilder.build();
        done.run(cresponse);
    }

    @Override
    public void commitRequest(RpcController controller, SsccCommitRequestRequest request,
            RpcCallback<SsccCommitRequestResponse> done) {

        SsccCommitRequestResponse response = SsccCommitRequestResponse.getDefaultInstance();
        long transId = request.getTransactionId();

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: commitRequest - id " + transId + ", regionName "
                    + regionInfo.getRegionNameAsString());

        int status = 0;
        IOException ioe = null;
        UnknownTransactionException ute = null;
        Throwable t = null;
        WrongRegionException wre = null;

        {
            // Process local memory
            try {
                status = commitRequest(transId);
            } catch (UnknownTransactionException u) {
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:commitRequest threw exception after internal commit"
                            + u.toString());
                ute = u;
            } catch (IOException e) {
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:commitRequest threw exception after internal commit"
                            + e.toString());
                ioe = e;
            }
        }

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCommitRequestResponse.Builder commitRequestResponseBuilder = SsccCommitRequestResponse
                .newBuilder();

        commitRequestResponseBuilder.setHasException(false);

        if (t != null) {
            commitRequestResponseBuilder.setHasException(true);
            commitRequestResponseBuilder.setException(t.toString());
        }

        if (wre != null) {
            commitRequestResponseBuilder.setHasException(true);
            commitRequestResponseBuilder.setException(wre.toString());
        }

        if (ioe != null) {
            commitRequestResponseBuilder.setHasException(true);
            commitRequestResponseBuilder.setException(ioe.toString());
        }

        if (ute != null) {
            commitRequestResponseBuilder.setHasException(true);
            commitRequestResponseBuilder.setException(ute.toString());
        }

        commitRequestResponseBuilder.setResult(status);

        SsccCommitRequestResponse cresponse = commitRequestResponseBuilder.build();
        done.run(cresponse);
    }

    /**
     * Commits the transaction
     * @param SsccTransactionState state
     * @throws IOException
     */
    private void commit(final SsccTransactionState state) throws IOException {
        long txid = 0;

        //if state is in ABORTED status, return do nothing
        if (state.getStatus() == Status.ABORTED || state.getStatus() == Status.COMMITED)
            return;

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  Commiting transaction: " + state.toString() + " to "
                    + m_Region.getRegionInfo().getRegionNameAsString());
        long inTransactionId = state.getTransactionId();
        long startId = state.getStartId();

        if (state.isReinstated()) {
            if (LOG.isTraceEnabled())
                LOG.trace(
                        "SsccRegionEndpoint coprocessor:  commit Trafodion Recovery: commit reinstated indoubt transactions "
                                + inTransactionId + " in region "
                                + m_Region.getRegionInfo().getRegionNameAsString());
            if (false) //Somthing wrong
            {
                state.setStatus(Status.ABORTED);
                retireTransaction(state);
            }
        } // reinstated transactions
        else {
            //get a commid ID  
            //  This commitId must be comparable with the startId
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: commit : try to update the status and version ");

            //       long commitId = nextSsccSequenceId.getAndIncrement();
            long commitId = state.getCommitId();

            //update the putlist
            List<byte[]> putToDoList = state.getPutRows();
            List<Delete> delToDoList = state.getDelRows();
            //List<Mutation> mutList= new ArrayList<Mutation>();
            try {
                for (byte[] rowkey : putToDoList) {
                    // delete the status item from status column for this transactin
                    Delete statusDelete = new Delete(rowkey, startId);
                    statusDelete.deleteColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.STATUS_COL);
                    //statusDelete.deleteColumn(DtmConst.TRANSACTION_META_FAMILY , SsccConst.COLUMNS_COL );
                    m_Region.delete(statusDelete);
                    //mutList.add(statusDelete);

                    // insert a new item into version column
                    //           Put verPut = new Put(rowkey, commitId.val);
                    Put verPut = new Put(rowkey, commitId);
                    verPut.add(DtmConst.TRANSACTION_META_FAMILY, SsccConst.VERSION_COL,
                            SsccConst.generateVersionValue(startId, false));
                    m_Region.put(verPut);
                    //mutList.add(verPut);
                }
                ListIterator<Delete> deletesIter = null;
                for (deletesIter = delToDoList.listIterator(); deletesIter.hasNext();) {
                    Delete d = deletesIter.next();

                    //mutList.add(d);
                    // insert a new item into version column
                    // delete the status item from status column for this transactin
                    byte[] dKey = d.getRow();
                    Delete statusDelete = new Delete(dKey, startId);
                    statusDelete.deleteColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.STATUS_COL);
                    //statusDelete.deleteColumn(DtmConst.TRANSACTION_META_FAMILY , SsccConst.COLUMNS_COL );
                    m_Region.delete(statusDelete);

                    //           Put verPut = new Put(dKey, commitId.val);
                    Put verPut = new Put(dKey, commitId);
                    verPut.add(DtmConst.TRANSACTION_META_FAMILY, SsccConst.VERSION_COL,
                            SsccConst.generateVersionValue(startId, true));
                    m_Region.put(verPut);
                    //           m_Region.delete(d);
                }
                //DO a batch mutation
                //Mutation[] m = (Mutation[])mutList.toArray();
                //m_Region.batchMutate(m);

                //set the commitId of the transaction
                //         state.setCommitId(commitId.val);
                //         state.setCommitId(commitId);
            } catch (Exception e) //something wrong
            {
                LOG.error("SsccRegionEndpoint Commit get exception " + e.toString());
                state.setStatus(Status.ABORTED);
                retireTransaction(state);
                throw new IOException(e.toString());
            }
        } // normal transactions

        // Now the transactional writes live in the core WAL, we can write a commit to the log
        // so we don't have to recover it from the transactional WAL.
        if (state.hasWrite() || state.isReinstated()) {
            // comment out for now
            if (LOG.isTraceEnabled())
                LOG.trace("write commit edit to HLOG");
            if (LOG.isTraceEnabled())
                LOG.trace("BBB write commit edit to HLOG after appendNoSync");
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:commit -- EXIT txId: " + inTransactionId + " HLog seq "
                        + txid);
            if (!editGenerated)
                editGenerated = true;
        }

        state.setStatus(Status.COMMITED);
        /*
            if (state.hasWrite() || state.isReinstated()) {
              synchronized (commitPendingTransactions) {
              if (!commitPendingTransactions.remove(state)) {
                  LOG.fatal("SsccRegionEndpoint coprocessor:  commit Commiting a non-query transaction that is not in commitPendingTransactions");
                  // synchronized statements are cleared for a throw
                throw new IOException("commit failure");
              }
            }
            }
        */

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  commit(tstate) -- EXIT SsccTransactionState: "
                    + state.toString());

        if (state.isReinstated()) {
            synchronized (indoubtTransactionsById) {
                indoubtTransactionsById.remove(state.getTransactionId());
                int tmid = (int) (inTransactionId >> 32);
                int count = 0;
                if (indoubtTransactionsCountByTmid.containsKey(tmid)) {
                    count = (int) indoubtTransactionsCountByTmid.get(tmid) - 1;
                    if (count > 0)
                        indoubtTransactionsCountByTmid.put(tmid, count);
                }
                if (count == 0) {
                    indoubtTransactionsCountByTmid.remove(tmid);
                    String lv_encoded = m_Region.getRegionInfo().getEncodedName();
                    try {
                        if (LOG.isTraceEnabled())
                            LOG.trace(
                                    "SsccRegionEndpoint coprocessor: commit Trafodion Recovery: delete in commit recovery zNode TM "
                                            + tmid + " region encoded name " + lv_encoded
                                            + " for 0 in-doubt transaction");
                        deleteRecoveryzNode(tmid, lv_encoded);
                    } catch (IOException e) {
                        LOG.error("Trafodion Recovery: delete recovery zNode failed");
                    }
                }

                if ((indoubtTransactionsById == null) || (indoubtTransactionsById.size() == 0)) {
                    if (indoubtTransactionsById == null)
                        if (LOG.isTraceEnabled())
                            LOG.trace(
                                    "SsccRegionEndpoint coprocessor:  commit Trafodion Recovery: start region in commit with indoubtTransactionsById null");
                        else if (LOG.isTraceEnabled())
                            LOG.trace(
                                    "SsccRegionEndpoint coprocessor:  commit Trafodion Recovery: start region in commit with indoubtTransactionsById size "
                                            + indoubtTransactionsById.size());
                    startRegionAfterRecovery();
                }
            }
        }
        retireTransaction(state);
    }

    /**
      * Commits the transaction
      * @param long TransactionId
      * @param boolean ignoreUnknownTransactionException
      * @throws IOException 
      */
    public void commit(final long transactionId, final long commitId,
            final boolean ignoreUnknownTransactionException) throws IOException {
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: commit -- ENTRY txId: " + transactionId + " commitId: "
                    + commitId + " ignoreUnknownTransactionException: " + ignoreUnknownTransactionException);
        SsccTransactionState state = null;
        try {
            state = getTransactionState(transactionId);
        } catch (UnknownTransactionException e) {
            if (ignoreUnknownTransactionException == true) {
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:  ignoring UnknownTransactionException in commit : "
                            + transactionId + " in region " + m_Region.getRegionInfo().getRegionNameAsString());
                return;
            }
            LOG.fatal("SsccRegionEndpoint coprocessor:  Asked to commit unknown transaction: " + transactionId
                    + " in region " + m_Region.getRegionInfo().getRegionNameAsString());
            throw new IOException("UnknownTransactionException");
        }
        /* SSCC don't need a prepare phase I
            if (!state.getStatus().equals(Status.COMMIT_PENDING)) {
              LOG.fatal("SsccRegionEndpoint coprocessor: commit - Asked to commit a non pending transaction ");
            
              throw new IOException("Asked to commit a non-pending transaction");
            }
        */
        state.setCommitId(commitId);

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: commit -- EXIT " + state);
        commit(state);
    }

    /**
     * @param transactionId
     * @return TransactionRegionInterface commit code
     * @throws IOException
     */
    public int commitRequest(final long transactionId) throws IOException {
        long txid = 0;

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: commitRequest -- ENTRY txId: " + transactionId);
        checkClosing(transactionId);
        SsccTransactionState state = null;
        try {
            state = getTransactionState(transactionId);
        } catch (UnknownTransactionException e) {
            return COMMIT_UNSUCCESSFUL;
        }

        if (state.hasWrite()) {
            return COMMIT_OK;
        }
        // Otherwise we were read-only and commitable, so we can forget it.
        state.setStatus(Status.COMMITED);
        retireTransaction(state);
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: commitRequest READ ONLY -- EXIT txId: " + transactionId);
        return COMMIT_OK_READ_ONLY;
    }

    /**
     * Commits the transaction
     * @param long TransactionId
     * @throws IOException
     */
    public void commit(final long transactionId, final long commitId) throws IOException {
        commit(transactionId, commitId, false /* IgnoreUnknownTransactionException */);
    }

    @Override
    public void abortTransaction(RpcController controller, SsccAbortTransactionRequest request,
            RpcCallback<SsccAbortTransactionResponse> done) {
        SsccAbortTransactionResponse response = SsccAbortTransactionResponse.getDefaultInstance();
        long transId = request.getTransactionId();

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: abortTransaction - id " + transId + ", regionName "
                    + regionInfo.getRegionNameAsString());

        IOException ioe = null;
        UnknownTransactionException ute = null;
        WrongRegionException wre = null;
        Throwable t = null;

        {
            // Process in local memory
            try {
                abortTransaction(transId);
            } catch (UnknownTransactionException u) {
                if (LOG.isTraceEnabled())
                    LOG.trace(
                            "SsccRegionEndpoint coprocessor:abort threw UnknownTransactionException after internal abort");
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:  Caught exception " + u.getMessage() + ""
                            + stackTraceToString(u));
                ute = u;
            } catch (IOException e) {
                if (LOG.isTraceEnabled())
                    LOG.trace(
                            "SsccRegionEndpoint coprocessor:abort threw UnknownTransactionException after internal abort");
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:  Caught exception " + e.getMessage() + ""
                            + stackTraceToString(e));
                ioe = e;
            }
        }

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccAbortTransactionResponse.Builder abortTransactionResponseBuilder = SsccAbortTransactionResponse
                .newBuilder();

        abortTransactionResponseBuilder.setHasException(false);

        if (t != null) {
            abortTransactionResponseBuilder.setHasException(true);
            abortTransactionResponseBuilder.setException(t.toString());
        }

        if (wre != null) {
            abortTransactionResponseBuilder.setHasException(true);
            abortTransactionResponseBuilder.setException(wre.toString());
        }

        if (ioe != null) {
            abortTransactionResponseBuilder.setHasException(true);
            abortTransactionResponseBuilder.setException(ioe.toString());
        }

        if (ute != null) {
            abortTransactionResponseBuilder.setHasException(true);
            abortTransactionResponseBuilder.setException(ute.toString());
        }

        SsccAbortTransactionResponse aresponse = abortTransactionResponseBuilder.build();

        done.run(aresponse);
    }

    /**
     * Abort the transaction.
     * 
     * @param transactionId
     * @throws IOException
     * @throws UnknownTransactionException
     */

    public void abortTransaction(final long transactionId) throws IOException, UnknownTransactionException {
        long txid = 0;
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: abort transactionId: " + transactionId + " "
                    + m_Region.getRegionInfo().getRegionNameAsString());

        SsccTransactionState state;
        try {
            state = getTransactionState(transactionId);
        } catch (UnknownTransactionException e) {
            IOException ioe = new IOException("UnknownTransactionException");
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: Unknown transaction [" + transactionId + "] in region ["
                        + m_Region.getRegionInfo().getRegionNameAsString() + "], " + ioe.toString());

            throw new IOException("UnknownTransactionException");
        }
        if (state.getStatus() == Status.ABORTED) {
            LOG.error("Transaction " + transactionId + " is already aborted, probably due to write conflict");
            return;
        }
        if (state.getStatus() == Status.COMMITED) //should be programming error in client. Like commmit() then abort()
        {
            LOG.error("Transaction " + transactionId + " is already committed, cannot perform abort anymore");
            return;
        }

        if (state.hasWrite()) {
            //get put/del list
            //do delet to undo put, do nothiing to undo del
            List<byte[]> putUndoList = ((SsccTransactionState) state).getPutRows();
            //List<Mutation> mutList = new ArrayList<Mutation>();
            for (byte[] rowkey : putUndoList) {
                long localTransId = state.getStartId();
                Delete d = new Delete(rowkey, localTransId);
                Get forColListGet = new Get(rowkey);
                forColListGet.setTimeStamp(localTransId); //get only those cells affected by the given transaction
                //perform a get first, parse the result and get all column affected by the put 
                Result r = m_Region.get(forColListGet);
                List<Cell> listCells = r.listCells();
                if (listCells != null) {
                    for (Cell cell : listCells) {
                        d.deleteColumn(CellUtil.cloneFamily(cell), CellUtil.cloneQualifier(cell), localTransId); //this is the cell that needs to be delete
                    }
                }
                m_Region.delete(d);
                //clear the status item
                Delete statusDelete = new Delete(rowkey, localTransId);
                statusDelete.deleteColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.STATUS_COL);
                //statusDelete.deleteColumn(DtmConst.TRANSACTION_META_FAMILY , SsccConst.COLUMNS_COL );
                m_Region.delete(statusDelete);
                //mutList.add(d);
            }

            //clear status
            List<Delete> deleteList = state.getDelRows();
            ListIterator<Delete> deletesIter = null;
            for (deletesIter = deleteList.listIterator(); deletesIter.hasNext();) {
                Delete di = deletesIter.next();

                long localTransId = state.getStartId();
                Delete d = new Delete(di.getRow(), localTransId);
                d.deleteColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.STATUS_COL);
                m_Region.delete(d);
            }

            /* not understand how to use batchMutate yet
            try {
              Mutation[] m = (Mutation[])mutList.toArray();
              m_Region.batchMutate(m);
            }
            catch (Exception e) {
              //TODO
              throw new IOException(e.toString());
            }
            */

        }
        synchronized (commitPendingTransactions) {
            commitPendingTransactions.remove(state);
        }

        if (state.isReinstated()) {
            synchronized (indoubtTransactionsById) {
                if (LOG.isTraceEnabled())
                    LOG.trace(
                            "SsccRegionEndpoint coprocessor: Trafodion Recovery: abort reinstated indoubt transactions "
                                    + transactionId);
                indoubtTransactionsById.remove(state.getTransactionId());
                int tmid = (int) (transactionId >> 32);
                int count = 0;

                // indoubtTransactionsCountByTmid protected by 
                // indoubtTransactionsById synchronization
                if (indoubtTransactionsCountByTmid.containsKey(tmid)) {
                    count = (int) indoubtTransactionsCountByTmid.get(tmid) - 1;
                    if (count > 0)
                        indoubtTransactionsCountByTmid.put(tmid, count);
                }

                // if all reinstated txns are resolved from a TM, remove it and delete associated zNode
                if (count == 0) {
                    indoubtTransactionsCountByTmid.remove(tmid);
                    String lv_encoded = m_Region.getRegionInfo().getEncodedName();
                    try {
                        if (LOG.isTraceEnabled())
                            LOG.trace(
                                    "SsccRegionEndpoint coprocessor: Trafodion Recovery: delete in abort recovery zNode TM "
                                            + tmid + " region encoded name " + lv_encoded
                                            + " for 0 in-doubt transaction");
                        deleteRecoveryzNode(tmid, lv_encoded);
                    } catch (IOException e) {
                        LOG.error(
                                "SsccRegionEndpoint coprocessor: Trafodion Recovery: delete recovery zNode failed");
                    }
                }

                if ((indoubtTransactionsById == null) || (indoubtTransactionsById.size() == 0)) {
                    // change region state to STARTED, and archive the split-thlog

                    if (indoubtTransactionsById == null)
                        if (LOG.isTraceEnabled())
                            LOG.trace(
                                    "SsccRegionEndpoint coprocessor: Trafodion Recovery: start region in abort with indoubtTransactionsById null");
                        else if (LOG.isTraceEnabled())
                            LOG.trace(
                                    "SsccRegionEndpoint coprocessor: Trafodion Recovery: start region in abort with indoubtTransactionsById size "
                                            + indoubtTransactionsById.size());
                    startRegionAfterRecovery();
                }
            }
        }
        state.setStatus(Status.ABORTED);
        retireTransaction(state);

    }

    /**
     * Determines if the transaction can be committed, and if possible commits the transaction.
     * @param long transactionId
     * @return boolean
     * @throws IOException
     */
    public boolean commitIfPossible(final long transactionId) throws IOException {

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  commitIfPossible -- ENTRY txId: " + transactionId);
        int status = commitRequest(transactionId);

        if (status == COMMIT_OK) {

            IdTmId seqId;
            try {
                seqId = new IdTmId();
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:  commitIfPossible:getting new IdTM sequence ");
                idServer.id(ID_TM_SERVER_TIMEOUT, seqId);
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:  commitIfPossible: IdTM sequence is " + seqId.val);
            } catch (IdTmException exc) {
                LOG.error("SsccRegionEndpoint coprocessor:  commitIfPossible: IdTm threw exception 1 " + exc);
                throw new IOException(
                        "SsccRegionEndpoint coprocessor:  commitIfPossible: IdTm threw exception 1 " + exc);
            } catch (Exception e2) {
                LOG.error("SsccRegionEndpoint coprocessor:  beginTransaction: IdTm threw exception e2 " + e2);
                throw new IOException(
                        "SsccRegionEndpoint coprocessor:  beginTransaction: IdTm threw exception e2 " + e2);
            }

            // Process local memory
            try {
                commit(transactionId, seqId.val);
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:  commitIfPossible -- ENTRY txId: " + transactionId
                            + " COMMIT_OK");
                return true;
            } catch (Throwable e) {
                if (LOG.isTraceEnabled())
                    LOG.trace(
                            "SsccRegionEndpoint coprocessor:coprocesor: commitIfPossible threw exception after internal commit");
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:  Caught exception " + e.getMessage() + ""
                            + stackTraceToString(e));
                throw new IOException(e.toString());
            }
        } else if (status == COMMIT_OK_READ_ONLY) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  commitIfPossible -- ENTRY txId: " + transactionId
                        + " COMMIT_OK_READ_ONLY");
            return true;
        }
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  commitIfPossible -- ENTRY txId: " + transactionId
                    + " Commit Unsuccessful");
        return false;
    }

    /***********************************************************************************
    *****************  ALL code to support SCAN   ************************************
    ***********************************************************************************/

    /**
     * Returns the scanner associated with the specified ID.
     *
     * @param long scannerId
     * @param long nextCallSeq
     * @return a Scanner or throws UnknownScannerException
     * @throws NotServingRegionException
     * @throws OutOfOrderscannerNextException
     * @throws UnknownScannerException
     */
    protected synchronized RegionScanner getScanner(long scannerId, long nextCallSeq)
            throws NotServingRegionException, OutOfOrderScannerNextException, UnknownScannerException {

        RegionScanner scanner = null;

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: getScanner scanners map is " + scanners + ", count is "
                    + scanners.size() + ", scanner id is " + scannerId);

        TransactionalRegionScannerHolder rsh = scanners.get(scannerId);

        if (rsh != null) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: getScanner rsh is " + rsh + "rsh.s is " + rsh.s);
        } else {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: getScanner rsh is null");
            throw new UnknownScannerException("ScannerId: " + scannerId + ", already closed?");
        }

        scanner = rsh.s;
        if (scanner != null) {
            HRegionInfo hri = scanner.getRegionInfo();
            if (this.m_Region != rsh.r) { // Yes, should be the same instance
                throw new NotServingRegionException("Region was re-opened after the scannerId" + scannerId
                        + " was created: " + hri.getRegionNameAsString());
            }
        }

        if (nextCallSeq != rsh.nextCallSeq) {
            if (LOG.isTraceEnabled())
                LOG.trace(
                        "SsccRegionEndpoint coprocessor: getScanner calling OutOfOrderScannerNextException, nextCallSeq is "
                                + nextCallSeq + " rsh.nextCallSeq is " + rsh.nextCallSeq);
            throw new OutOfOrderScannerNextException("Expected nextCallSeq: " + rsh.nextCallSeq
                    + " But the nextCallSeq got from client: " + nextCallSeq);
        }

        return scanner;
    }

    @Override
    public void performScan(RpcController controller, SsccPerformScanRequest request,
            RpcCallback<SsccPerformScanResponse> done) {

        boolean hasMore = true;
        RegionScanner scanner = null;
        Throwable t = null;
        ScannerTimeoutException ste = null;
        OutOfOrderScannerNextException ooo = null;
        WrongRegionException wre = null;
        Exception ne = null;
        Scan scan = null;
        List<Cell> cellResults = new ArrayList<Cell>();
        List<Result> results = new ArrayList<Result>();
        List<Cell> validResults = new ArrayList<Cell>();
        org.apache.hadoop.hbase.client.Result result = null;
        long transId = request.getTransactionId();
        long startId = request.getStartId();

        long scannerId = request.getScannerId();
        int numberOfRows = request.getNumberOfRows();
        boolean closeScanner = request.getCloseScanner();
        long nextCallSeq = request.getNextCallSeq();
        long count = 0L;
        boolean shouldContinue = true;

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: performScan - scannerId " + scannerId + ", numberOfRows "
                    + numberOfRows + ", nextCallSeq " + nextCallSeq);

        //This may be wrong, check later
        Map<String, Cell> tempBuf = new TreeMap<String, Cell>();

        try {

            scanner = getScanner(scannerId, nextCallSeq);
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: performScan - scanner is: " + scanner == null ? "NULL"
                        : "NOT NULL");

            SsccTransactionState state = this.beginTransIfNotExist(transId, startId);
            Set<byte[]> visitCols = new HashSet<byte[]>();

            if (scanner != null) {
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor: performScan - id " + scannerId
                            + ", scanner is not null");
                boolean firstCell = true;

                while (shouldContinue) {
                    hasMore = scanner.next(cellResults);
                    if (LOG.isTraceEnabled())
                        LOG.trace("SsccRegionEndpoint coprocessor: performScan hasMore is: " + hasMore);
                    firstCell = true;
                    Result verResult = null;
                    Result statusResult = null;
                    Result colResult = null;
                    tempBuf.clear();

                    ListIterator<Cell> cellIter = null;
                    for (cellIter = cellResults.listIterator(); cellIter.hasNext();) {
                        Cell c = cellIter.next();
                        if (firstCell == true) {
                            if (CellUtil.cloneFamily(c) != DtmConst.TRANSACTION_META_FAMILY) {
                                //get the statusList
                                Get statusGet = new Get(c.getRow()); //TODO: deprecated API
                                //statusGet.setTimeStamp(startId);
                                statusGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.STATUS_COL);
                                statusGet.setMaxVersions(DtmConst.MAX_VERSION);
                                statusResult = m_Region.get(statusGet);

                                //get the colList
                                Get colGet = new Get(c.getRow()); //TODO: deprecated API
                                //colGet.setTimeStamp(startId);
                                colGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.COLUMNS_COL);
                                colGet.setMaxVersions(DtmConst.MAX_VERSION);
                                colResult = m_Region.get(colGet);

                                //get the versionList
                                Get verGet = new Get(c.getRow());//TODO: deprecated API
                                //verGet.setTimeStamp(startId);
                                verGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.VERSION_COL);
                                verGet.setMaxVersions(DtmConst.MAX_VERSION);
                                verResult = m_Region.get(verGet);
                                firstCell = false;
                            }
                        }

                        //long kvStartId = getStartIdFromTs(thisTs);
                        if (firstCell == false) {

                            //long thisTs = c.getTimestamp();
                            if (state.handleResult(c, statusResult.listCells(), verResult.listCells(),
                                    colResult.listCells(), transId) == true) {
                                byte[] keyt = CellUtil.cloneQualifier(c);
                                String keys = new String(keyt);
                                if (tempBuf.containsKey(keys) == false) //only get the first one, suppose first is latest
                                    tempBuf.put(keys, c);
                            }
                        }
                    }
                    for (String j : tempBuf.keySet()) {
                        Cell kv = tempBuf.get(j);
                        validResults.add(kv);
                    }

                    result = Result.create(validResults);
                    cellResults.clear();
                    validResults.clear();
                    if (!result.isEmpty()) {
                        results.add(result);
                        count++;
                    }

                    if (count == numberOfRows || !hasMore)
                        shouldContinue = false;
                    if (LOG.isTraceEnabled())
                        LOG.trace("SsccRegionEndpoint coprocessor: performScan - id " + scannerId + ", count is "
                                + count + ", hasMore is " + hasMore + ", result " + result.isEmpty() + ", row "
                                + result.getRow());
                }
            } else {
                if (LOG.isTraceEnabled())
                    LOG.trace(
                            "SsccRegionEndpoint coprocessor: performScan - id " + scannerId + ", scanner is null");
            }

        } catch (OutOfOrderScannerNextException ooone) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: performScan - id " + scannerId
                        + " Caught OutOfOrderScannerNextException  " + ooone.getMessage() + " "
                        + stackTraceToString(ooone));
            ooo = ooone;
        } catch (ScannerTimeoutException cste) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: performScan - id " + scannerId
                        + " Caught ScannerTimeoutException  " + cste.getMessage() + " " + stackTraceToString(cste));
            ste = cste;
        } catch (Throwable e) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: performScan - id " + scannerId + " Caught exception  "
                        + e.getMessage() + " " + stackTraceToString(e));
            t = e;
        } finally {
            if (scanner != null) {
                try {
                    if (closeScanner) {
                        scanner.close();
                        /*
                                     try {
                                       scannerLeases.cancelLease(getScannerLeaseId(scannerId));
                                     } catch (LeaseException le) {
                                       // ignore
                                       if (LOG.isTraceEnabled()) LOG.trace("SsccRegionEndpoint coprocessor: performScan failed to get a lease " + scannerId);
                                     }
                        */
                    }
                } catch (Exception e) {
                    if (LOG.isTraceEnabled())
                        LOG.trace("SsccRegionEndpoint coprocessor:  performScan caught exception " + e.getMessage()
                                + "" + stackTraceToString(e));
                    ne = e;
                }
            }
        }

        TransactionalRegionScannerHolder rsh = scanners.get(scannerId);

        nextCallSeq++;

        rsh.nextCallSeq = nextCallSeq;

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: performScan - id " + transId + ", regionName "
                    + regionInfo.getRegionNameAsString() + ", scannerId " + scannerId + ", nextCallSeq "
                    + nextCallSeq + ", rsh.nextCallSeq " + rsh.nextCallSeq);
        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccPerformScanResponse.Builder performResponseBuilder = SsccPerformScanResponse
                .newBuilder();
        performResponseBuilder.setHasMore(hasMore);
        performResponseBuilder.setNextCallSeq(nextCallSeq);
        performResponseBuilder.setCount(count);
        performResponseBuilder.setHasException(false);

        if (results != null) {
            if (!results.isEmpty()) {
                ListIterator<Result> resultIter = null;
                for (resultIter = results.listIterator(); resultIter.hasNext();) {
                    Result r = resultIter.next();
                    performResponseBuilder.addResult(ProtobufUtil.toResult(r));
                    //          LOG.info("UNIQUE: performScan return row " + Arrays.toString(r.getRow()) );
                    //          for( Cell c : r.listCells() ) {
                    //            LOG.info("UNIQUE: performScan return value col : " + Arrays.toString(CellUtil.cloneQualifier(c) )+ " value " + Arrays.toString(CellUtil.cloneValue(c) ) );
                    //          }
                    //          LOG.info("UNIQUE : -- ");
                }
            }
        }

        if (t != null) {
            performResponseBuilder.setHasException(true);
            performResponseBuilder.setException(t.toString());
        }

        if (ste != null) {
            performResponseBuilder.setHasException(true);
            performResponseBuilder.setException(ste.toString());
        }

        if (wre != null) {
            performResponseBuilder.setHasException(true);
            performResponseBuilder.setException(wre.toString());
        }

        if (ne != null) {
            performResponseBuilder.setHasException(true);
            performResponseBuilder.setException(ne.toString());
        }

        if (ooo != null) {
            performResponseBuilder.setHasException(true);
            performResponseBuilder.setException(ooo.toString());
        }
        SsccPerformScanResponse presponse = performResponseBuilder.build();
        done.run(presponse);
    }

    @Override
    public void openScanner(RpcController controller, SsccOpenScannerRequest request,
            RpcCallback<SsccOpenScannerResponse> done) {
        boolean hasMore = true;
        RegionScanner scanner = null;
        RegionScanner scannert = null;
        Throwable t = null;
        WrongRegionException wre = null;
        boolean exceptionThrown = false;
        NullPointerException npe = null;
        Exception ge = null;
        IOException ioe = null;
        LeaseStillHeldException lse = null;
        Scan scan = null;
        long scannerId = 0L;
        boolean isLoadingCfsOnDemandSet = false;
        long transId = request.getTransactionId();
        long startId = request.getStartId();

        {

            try {
                scan = ProtobufUtil.toScan(request.getScan());
                if (scan == null)
                    if (LOG.isTraceEnabled())
                        LOG.trace("SsccRegionEndpoint coprocessor:  openScanner scan was null");
            } catch (Throwable e) {
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:  openScanner Caught exception " + e.getMessage() + ""
                            + stackTraceToString(e));
                t = e;
                exceptionThrown = true;
            }
        }

        if (!exceptionThrown) {
            if (scan == null) {
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:openScanner scan is null");
                npe = new NullPointerException("scan is null");
                ioe = new IOException("Invalid arguments to openScanner", npe);
                exceptionThrown = true;
            } else {
                try {
                    scan.getAttribute(Scan.SCAN_ATTRIBUTES_METRICS_ENABLE);
                    //checkRow(scan.getStartRow(), "Scan");            
                    prepareScanner(scan);
                } catch (Throwable e) {
                    if (LOG.isTraceEnabled())
                        LOG.trace("SsccRegionEndpoint coprocessor:openScanner scan threw exception");
                    if (LOG.isTraceEnabled())
                        LOG.trace("SsccRegionEndpoint coprocessor:  Caught exception " + e.getMessage() + ""
                                + stackTraceToString(e));
                    t = e;
                    exceptionThrown = true;
                }
            }
        }

        List<Cell> results = new ArrayList<Cell>();

        if (!exceptionThrown) {
            try {
                scan.setMaxVersions();
                scanner = getScanner(transId, startId, scan);
                if (scanner != null) {
                    if (LOG.isTraceEnabled())
                        LOG.trace("SsccRegionEndpoint coprocessor:  openScanner called getScanner, scanner is "
                                + scanner + ", transid " + transId);
                    // Add the scanner to the map
                    scannerId = addScanner(transId, scanner, this.m_Region);
                    if (LOG.isTraceEnabled())
                        LOG.trace("SsccRegionEndpoint coprocessor:  openScanner called addScanner, scannerId is "
                                + scannerId + ", transid " + transId);
                } else {
                    if (LOG.isTraceEnabled())
                        LOG.trace("SsccRegionEndpoint coprocessor:  getScanner returned null, scannerId is "
                                + scannerId + ", transid " + transId);
                }
            } catch (LeaseStillHeldException llse) {

                LOG.error("SsccRegionEndpoint coprocessor:  getScanner Error opening scanner, " + llse.toString());
                exceptionThrown = true;
                lse = llse;
            } catch (IOException e) {
                LOG.error("SsccRegionEndpoint coprocessor:  getScanner Error opening scanner, " + e.toString());
                exceptionThrown = true;
            }
        }

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: openScanner - transid " + transId + ", regionName "
                    + regionInfo.getRegionNameAsString());

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccOpenScannerResponse.Builder openResponseBuilder = SsccOpenScannerResponse
                .newBuilder();

        openResponseBuilder.setScannerId(scannerId);
        openResponseBuilder.setHasException(false);

        if (t != null) {
            openResponseBuilder.setHasException(true);
            openResponseBuilder.setException(t.toString());
        }

        if (wre != null) {
            openResponseBuilder.setHasException(true);
            openResponseBuilder.setException(wre.toString());
        }

        if (ioe != null) {
            openResponseBuilder.setHasException(true);
            openResponseBuilder.setException(ioe.toString());
        }

        if (lse != null) {
            openResponseBuilder.setHasException(true);
            openResponseBuilder.setException(lse.toString());
        }

        SsccOpenScannerResponse oresponse = openResponseBuilder.build();
        done.run(oresponse);
    }

    /**
     * Obtain a RegionScanner
     * @param long transactionId
     * @param Scan scan
     * @return RegionScanner
     * @throws IOException 
     */
    public RegionScanner getScanner(final long transactionId, final long startId, final Scan scan)
            throws IOException {

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  RegionScanner getScanner -- ENTRY txId: " + transactionId);

        SsccTransactionState state = this.beginTransIfNotExist(transactionId, startId);

        //state.addScan(scan);

        List<KeyValueScanner> scanners = new ArrayList<KeyValueScanner>(1);

        //Scan deleteWrapScan = wrapWithDeleteFilter(scan, state);
        //In SSCC, we cannot find a way to do this with Filter...

        if (LOG.isTraceEnabled())
            LOG.trace(
                    "SsccRegionEndpoint coprocessor:  RegionScanner getScanner -- Calling t_Region.getScanner txId: "
                            + transactionId);
        RegionScanner gotScanner = this.t_Region.getScanner(scan);
        if (gotScanner != null)
            if (LOG.isTraceEnabled())
                LOG.trace(
                        "SsccRegionEndpoint coprocessor:  RegionScanner getScanner -- obtained scanner was not null,  txId: "
                                + transactionId);
            else if (LOG.isTraceEnabled())
                LOG.trace(
                        "SsccRegionEndpoint coprocessor:  RegionScanner getScanner -- obtained scanner was null,  txId: "
                                + transactionId);
        return gotScanner;
    }

    @Override
    public void closeScanner(RpcController controller, SsccCloseScannerRequest request,
            RpcCallback<SsccCloseScannerResponse> done) {

        RegionScanner scanner = null;
        Throwable t = null;
        WrongRegionException wre = null;
        Exception ce = null;
        long transId = request.getTransactionId();
        long scannerId = request.getScannerId();

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: closeScanner - transId " + transId + ", regionName "
                    + regionInfo.getRegionNameAsString() + ", scannerId " + scannerId);

        try {
            scanner = removeScanner(scannerId);

            if (scanner != null) {
                scanner.close();
            } else if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  closeScanner scanner was null for scannerId "
                        + scannerId);

            /*
                     try {
                       scannerLeases.cancelLease(getScannerLeaseId(scannerId));
                     } catch (LeaseException le) {
                       // ignore
                       if (LOG.isTraceEnabled()) LOG.trace("SsccRegionEndpoint coprocessor: closeScanner failed to get a lease " + scannerId);
                     }
            */

        } catch (Exception e) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  closeScanner caught exception " + e.getMessage() + ""
                        + stackTraceToString(e));
            ce = e;
        } catch (Throwable e) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: closeScanner - id Caught exception  " + e.getMessage()
                        + " " + stackTraceToString(e));
            t = e;
        }

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCloseScannerResponse.Builder closeResponseBuilder = SsccCloseScannerResponse
                .newBuilder();

        closeResponseBuilder.setHasException(false);

        if (t != null) {
            closeResponseBuilder.setHasException(true);
            closeResponseBuilder.setException(t.toString());
        }

        if (wre != null) {
            closeResponseBuilder.setHasException(true);
            closeResponseBuilder.setException(wre.toString());
        }

        if (ce != null) {
            closeResponseBuilder.setHasException(true);
            closeResponseBuilder.setException(ce.toString());
        }

        SsccCloseScannerResponse cresponse = closeResponseBuilder.build();
        done.run(cresponse);
    }

    /***********************************************************************************
    *****************  ALL code to support GET    ************************************
    ***********************************************************************************/

    @Override
    public void get(RpcController controller, SsccGetTransactionalRequest request,
            RpcCallback<SsccGetTransactionalResponse> done) {
        SsccGetTransactionalResponse response = SsccGetTransactionalResponse.getDefaultInstance();

        org.apache.hadoop.hbase.protobuf.generated.ClientProtos.Get proto = request.getGet();
        Get get = null;
        RegionScanner scanner = null;
        Throwable t = null;
        Exception ge = null;
        WrongRegionException wre = null;
        org.apache.hadoop.hbase.client.Result result2 = null;

        try {
            get = ProtobufUtil.toGet(proto);
        } catch (Throwable e) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:get threw exception");
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  Caught exception " + e.getMessage() + ""
                        + stackTraceToString(e));
            t = e;
        }

        byte[] row = proto.getRow().toByteArray();
        byte[] getrow = get.getRow();
        String rowKey = Bytes.toString(row);
        String getRowKey = Bytes.toString(getrow);
        long transId = request.getTransactionId();
        long startId = request.getStartId();

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: get - id " + transId + ", regionName "
                    + regionInfo.getRegionNameAsString() + ", row = " + rowKey + ", getRowKey = " + getRowKey);

        try {

            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: get - id Calling getScanner id/scan " + transId
                        + ", regionName " + regionInfo.getRegionNameAsString() + ", row = " + rowKey
                        + ", getRowKey = " + getRowKey);

            result2 = get(transId, startId, get);

            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: get - id No exception, result2 isEmpty is "
                        + result2.isEmpty() + ", row " + result2.getRow() + " result length: " + result2.size());

        } catch (Throwable e) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: get - id Caught exception  " + e.getMessage() + " "
                        + stackTraceToString(e));
            t = e;
        } finally {
            if (scanner != null) {
                try {
                    scanner.close();
                } catch (Exception e) {
                    if (LOG.isTraceEnabled())
                        LOG.trace("SsccRegionEndpoint coprocessor:  Caught exception " + e.getMessage() + ""
                                + stackTraceToString(e));
                    ge = e;
                }
            }
        }

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccGetTransactionalResponse.Builder getResponseBuilder = SsccGetTransactionalResponse
                .newBuilder();

        try {
            getResponseBuilder.setResult(ProtobufUtil.toResult(result2));
        } catch (Exception e) {
            LOG.error("SsccRegionEndpoint coprocessor:  Caught exception getting result2 " + result2 + " "
                    + stackTraceToString(e));
        }
        /*
        if(result2 !=null){
        LOG.info("UNIQUE: get result for row " + Arrays.toString(result2.getRow() ));
            
        for( Cell c : result2.listCells() )
        {
        LOG.info("UNIQUE: get return value col : " + Arrays.toString(CellUtil.cloneQualifier(c) )+ " value " + Arrays.toString(CellUtil.cloneValue(c) ) );    
        }
        }
        */

        getResponseBuilder.setHasException(false);

        if (t != null) {
            getResponseBuilder.setHasException(true);
            getResponseBuilder.setException(t.toString());
        }

        if (wre != null) {
            getResponseBuilder.setHasException(true);
            getResponseBuilder.setException(wre.toString());
        }

        if (ge != null) {
            getResponseBuilder.setHasException(true);
            getResponseBuilder.setException(ge.toString());
        }

        SsccGetTransactionalResponse gresponse = getResponseBuilder.build();
        done.run(gresponse);
    }

    /**
     * Obtains a transactional Result for Get          
     * @param long transactionId
     * @param Get get             
     * @return Result 
     * @throws IOException 
     */
    public Result get(final long transactionId, final long startId, final Get get) throws IOException {
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  get --  ENTRY txId: " + transactionId + " startId: "
                    + startId);
        //get thet state object
        SsccTransactionState state = this.beginTransIfNotExist(transactionId, startId);

        Scan scan = new Scan(get);

        List<Cell> results = new ArrayList<Cell>();
        RegionScanner scanner = null;
        long max = scan.getTimeRange().getMax();
        long min = scan.getTimeRange().getMin();

        scan.setTimeRange(0, startId + 1); //only get data updated before me 
        scan.setMaxVersions(DtmConst.MAX_VERSION);

        Map<String, Cell> tempBuf = new TreeMap<String, Cell>();

        try {
            scanner = m_Region.getScanner(scan);

            //get the statusList
            Get statusGet = new Get(get.getRow());//TODO: deprecated API
            //statusGet.setTimeStamp(startId);
            statusGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.STATUS_COL);
            statusGet.setMaxVersions(DtmConst.MAX_VERSION);
            Result statusResult = m_Region.get(statusGet);

            //get the versionList
            Get verGet = new Get(get.getRow());//TODO: deprecated API
            //verGet.setTimeStamp(startId);
            verGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.VERSION_COL);
            verGet.setMaxVersions(DtmConst.MAX_VERSION);
            Result verResult = m_Region.get(verGet);

            //get the colList
            Get colGet = new Get(get.getRow()); //TODO: deprecated API
            //colGet.setTimeStamp(startId);
            colGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.COLUMNS_COL);
            colGet.setMaxVersions(DtmConst.MAX_VERSION);
            Result colResult = m_Region.get(colGet);

            /* go through all the versions and find out correct one */
            boolean hasMore = false;
            List<Cell> eachVersion = new ArrayList<Cell>();
            Set<byte[]> visitCols = new HashSet<byte[]>();

            List<Cell> sl = statusResult.listCells();
            List<Cell> vl = verResult.listCells();
            List<Cell> cl = colResult.listCells();

            do {
                eachVersion.clear();
                hasMore = scanner.next(eachVersion);
                tempBuf.clear();
                for (Cell kv : eachVersion) {
                    long thisTs = kv.getTimestamp();
                    //find out the startId for thisTs
                    //long kvStartId = getStartIdFromTs(thisTs);
                    if (state.handleResult(kv, sl, vl, cl, transactionId) == true) {
                        byte[] keyt = CellUtil.cloneQualifier(kv);
                        String keys = new String(keyt);
                        if (tempBuf.containsKey(keys) == false)
                            tempBuf.put(keys, kv);
                    }
                }
                for (String j : tempBuf.keySet()) {
                    Cell kv = tempBuf.get(j);
                    results.add(kv);
                }
            } while (hasMore);
        } catch (Exception e) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  get Caught exception " + e.getMessage() + ""
                        + stackTraceToString(e));
            LOG.error("SsccRegionEndpoint coprocessor:  get Caught exception " + e.getMessage() + ""
                    + stackTraceToString(e));
        } finally {
            if (scanner != null) {
                scanner.close();
            }
        }
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  get -- EXIT txId: " + transactionId);
        return Result.create(results);
    }

    /***********************************************************************************
    *****************  ALL code to support stateless/stateful PUT   ********************
    ***********************************************************************************/

    @Override
    public void put(RpcController controller, SsccPutTransactionalRequest request,
            RpcCallback<SsccPutTransactionalResponse> done) {
        SsccPutTransactionalResponse response = SsccPutTransactionalResponse.getDefaultInstance();

        boolean stateless = false;
        if (request.hasIsStateless()) {
            stateless = request.getIsStateless();
        }
        byte[] row = null;
        MutationProto proto = request.getPut();
        MutationType type = proto.getMutateType();
        Put put = null;
        Throwable t = null;
        WrongRegionException wre = null;
        int status = 0;
        long transId = request.getTransactionId();
        long startId = request.getStartId();
        try {
            put = ProtobufUtil.toPut(proto);
        } catch (Throwable e) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:put threw exception");
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  Caught exception " + e.getMessage() + ""
                        + stackTraceToString(e));
            LOG.error("UNIQUE coprocessor:  Caught exception " + e.getMessage() + "" + stackTraceToString(e));
            t = e;
        }

        if (type == MutationType.PUT && proto.hasRow()) {
            row = proto.getRow().toByteArray();

            // Process in local memory
            try {
                status = put(transId, startId, put, stateless);
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:put returned status: " + status);
            } catch (Throwable e) {
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:put threw exception after internal put");
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:  Caught exception " + e.getMessage() + ""
                            + stackTraceToString(e));
                t = e;
            }

            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: put - id " + transId + ", regionName "
                        + regionInfo.getRegionNameAsString() + ", type " + type + ", row " + Bytes.toString(row));
        } else {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: put - id " + transId + ", regionName "
                        + regionInfo.getRegionNameAsString() + "- no valid PUT type or does not contain a row");
        }

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccPutTransactionalResponse.Builder putTransactionalResponseBuilder = SsccPutTransactionalResponse
                .newBuilder();

        putTransactionalResponseBuilder.setHasException(false);

        if (t != null) {
            putTransactionalResponseBuilder.setHasException(true);
            putTransactionalResponseBuilder.setException(t.toString());
        }

        if (wre != null) {
            putTransactionalResponseBuilder.setHasException(true);
            putTransactionalResponseBuilder.setException(wre.toString());
        }

        putTransactionalResponseBuilder.setStatus(status);

        SsccPutTransactionalResponse presponse = putTransactionalResponseBuilder.build();
        done.run(presponse);
    }

    /**
     * Add a write to the transaction.
     * process.
     * @param long transactionId
     * @param Put put
     * @param boolean stateless  // Is this a stateless put?
     * @return int
     * @throws IOException
     */

    public int put(final long transactionId, final long startId, final Put put, boolean stateless)
            throws IOException {
        if (LOG.isTraceEnabled())
            LOG.trace("Enter SsccRegionEndpoint coprocessor: put, txid " + transactionId + ", startId " + startId
                    + ", stateless: " + stateless);
        SsccTransactionState state = this.beginTransIfNotExist(transactionId, startId);

        // check whether has del before
        state.removeDelBeforePut(put, stateless);

        /*need to change the timestamp, but HBase API does not support
          At this point, the solution is to create a new Put object
        */
        //So the solution at this point is
        //add a mapping of current timestamp of the put row with the startId
        //mapStartIdFromTs(put.getTimeStamp(),startId);
        // try to use getFamilyCellMap to get out all data from the put object and generate a new one
        byte[] rowkey = put.getRow();
        Put newPut = new Put(rowkey, startId);
        byte[] mergedCols = null;
        byte[] mergedColsV = null;
        byte[] cv = null;
        NavigableMap<byte[], List<Cell>> familyCellMap = put.getFamilyCellMap();
        for (Entry<byte[], List<Cell>> entry : familyCellMap.entrySet()) {
            for (Iterator<Cell> iterator = entry.getValue().iterator(); iterator.hasNext();) {
                Cell cell = iterator.next();
                byte[] family = CellUtil.cloneFamily(cell);
                byte[] qualifier = CellUtil.cloneQualifier(cell);
                mergedCols = null;
                mergedCols = byteMerger("|".getBytes(), qualifier);
                mergedCols = byteMerger(mergedCols, "|".getBytes());
                byte[] value = CellUtil.cloneValue(cell);
                newPut.add(family, qualifier, startId, value);
                byte[] currentCollist = state.getColList(rowkey);
                if (indexOf(currentCollist, mergedCols) != -1) //already in this list
                {
                    mergedColsV = byteMerger(currentCollist, null);
                    continue;
                }
                mergedColsV = byteMerger(mergedCols, currentCollist);
                state.addToColList(rowkey, mergedColsV);
            }
        }

        //get the statusList
        Get statusGet = new Get(rowkey);
        //statusGet.setTimeStamp(startId);
        statusGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.STATUS_COL);
        //statusGet.setTimeRange(0, startId + 1);  //only get data updated before me
        //statusGet.setMaxVersions(DtmConst.MAX_VERSION);
        statusGet.setMaxVersions();

        Result statusResult = m_Region.get(statusGet);

        List<Cell> sl = null;
        List<Cell> vl = null;

        //get the versionList
        //  If this is a stateless put we don't need the version list
        if (stateless == false) {
            Get verGet = new Get(rowkey);

            //verGet.setTimeStamp(startId);
            verGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.VERSION_COL);
            verGet.setMaxVersions(DtmConst.MAX_VERSION);

            Result verResult = m_Region.get(verGet);
            if (verResult != null)
                vl = verResult.listCells();
        }

        if (statusResult != null)
            sl = statusResult.listCells();
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: put stateless: " + stateless);
        if (state.hasConflict(sl, vl, stateless, startId, transactionId) == false) {
            state.addToPutList(rowkey);
            //update status metadata
            byte[] statusValue;
            if (stateless) {
                statusValue = SsccConst.generateStatusValue(SsccConst.S_STATELESS_BYTE, transactionId); //stateless update
            } else {
                statusValue = SsccConst.generateStatusValue(SsccConst.S_STATEFUL_BYTE, transactionId); //stateful update
            }
            newPut.add(DtmConst.TRANSACTION_META_FAMILY, SsccConst.STATUS_COL, startId, statusValue);
            newPut.add(DtmConst.TRANSACTION_META_FAMILY, SsccConst.COLUMNS_COL, startId, mergedColsV);
            //perform the put operation, persistently save the data now.
            //        LOG.info("UNIQUE: put ok "   );
            m_Region.put(newPut);
            return stateless ? STATELESS_UPDATE_OK : STATEFUL_UPDATE_OK;

        } else { //conflict
                 // Return conflict, but don't trigger and abort.  That needs to be triggered from the client, if desired.
            if (LOG.isTraceEnabled())
                LOG.trace("UNIQUE: put STATEFUL_UPDATE_CONFLICT ");
            return stateless ? STATELESS_UPDATE_CONFLICT : STATEFUL_UPDATE_CONFLICT;
        }
    }

    /***********************************************************************************
    *****************  ALL code to support DELETE   ************************************
    ***********************************************************************************/
    @Override
    public void delete(RpcController controller, SsccDeleteTransactionalRequest request,
            RpcCallback<SsccDeleteTransactionalResponse> done) {
        SsccDeleteTransactionalResponse response = SsccDeleteTransactionalResponse.getDefaultInstance();

        byte[] row = null;
        MutationProto proto = request.getDelete();
        MutationType type = proto.getMutateType();
        Delete delete = null;
        Throwable t = null;
        WrongRegionException wre = null;
        long transId = request.getTransactionId();
        long startId = request.getStartId();

        if (wre == null && type == MutationType.DELETE && proto.hasRow())
            row = proto.getRow().toByteArray();
        try {
            delete = ProtobufUtil.toDelete(proto);
        } catch (Throwable e) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:delete threw exception");
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  Caught exception " + e.getMessage() + " "
                        + stackTraceToString(e));
            t = e;
        }

        // Process in local memory
        int status = 0;
        try {
            status = delete(transId, startId, delete);
        } catch (Throwable e) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:delete threw exception after internal delete");
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  Caught exception " + e.getMessage() + ""
                        + stackTraceToString(e));
            t = e;
        }

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: delete - id " + transId + ", regionName "
                    + regionInfo.getRegionNameAsString() + ", type " + type + ", row " + Bytes.toString(row));

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccDeleteTransactionalResponse.Builder deleteTransactionalResponseBuilder = SsccDeleteTransactionalResponse
                .newBuilder();

        deleteTransactionalResponseBuilder.setHasException(false);

        if (t != null) {
            deleteTransactionalResponseBuilder.setHasException(true);
            deleteTransactionalResponseBuilder.setException(t.toString());
        }

        if (wre != null) {
            deleteTransactionalResponseBuilder.setHasException(true);
            deleteTransactionalResponseBuilder.setException(wre.toString());
        }

        deleteTransactionalResponseBuilder.setStatus(status);

        SsccDeleteTransactionalResponse dresponse = deleteTransactionalResponseBuilder.build();
        done.run(dresponse);
    }

    /**
     * Processes a transactional delete
     * @param long transactionId
     * @param Delete delete
     * @return int
     * @throws IOException
     */
    public int delete(final long transactionId, final long startId, final Delete delete) throws IOException {
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: delete -- ENTRY txId: " + transactionId + ", startId:"
                    + startId);
        checkClosing(transactionId);
        SsccTransactionState state = this.beginTransIfNotExist(transactionId, startId);

        //clone the delete
        //just to change the timestamp. But I hope the overhead is not too big a concern here
        byte[] rowkey = delete.getRow();
        Delete newDelete = new Delete(rowkey, startId);
        NavigableMap<byte[], List<Cell>> familyCellMap = delete.getFamilyCellMap();
        byte[] mergedColsV = null;
        byte[] cv = null;
        for (Entry<byte[], List<Cell>> entry : familyCellMap.entrySet()) {
            for (Iterator<Cell> iterator = entry.getValue().iterator(); iterator.hasNext();) {
                Cell cell = iterator.next();
                byte[] family = CellUtil.cloneFamily(cell);
                byte[] qualifier = CellUtil.cloneQualifier(cell);
                cv = null;
                cv = byteMerger("|".getBytes(), null);
                cv = byteMerger(cv, qualifier);
                cv = byteMerger(cv, "|".getBytes());
                byte[] currentCollist = state.getColList(rowkey);
                newDelete.deleteColumns(family, qualifier, startId); //NOTE: HBase 1.0 this API will change ...
                //here use deleteColumns with timestamp, so it will delete all history version of this row
                //but the real delete is not done at this point, but when doCommit
                //Only when it goes to doCommit(), it is safe to delete all versions
                //Otherwise, SSCC use MVCC in hbase to save history versions, those versions may need in other transaction
                //  to get a snapshot value in the before.
                //Another choice here is to use deleteColumn instead of using deleteColumns, so it will only delete the specific version
                //  specified by the startId. But I suppose these two methods are same. Need more test maybe.

                if (indexOf(currentCollist, cv) != -1) //already in this list
                {
                    mergedColsV = byteMerger(currentCollist, null);
                    continue;
                }
                mergedColsV = byteMerger(currentCollist, cv);
                state.addToColList(rowkey, mergedColsV);
            }
        }
        Get statusGet = new Get(rowkey);
        statusGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.STATUS_COL);
        statusGet.setMaxVersions();
        Result statusResult = m_Region.get(statusGet);
        List<Cell> sl = null;
        if (statusResult != null)
            sl = statusResult.listCells();

        // All deletes are treated as stateless, so no need to retrieve the versions
        if (state.hasConflict(sl, null, true, startId, transactionId) == false) {
            state.addToDelList(newDelete);
            /*update the status metadata*/
            Put statusPut = new Put(rowkey, startId);
            byte[] statusValue;
            statusValue = SsccConst.generateStatusValue(SsccConst.S_DELETE_BYTE, transactionId); //stateless delete
            statusPut.add(DtmConst.TRANSACTION_META_FAMILY, SsccConst.STATUS_COL, startId, statusValue);
            statusPut.add(DtmConst.TRANSACTION_META_FAMILY, SsccConst.COLUMNS_COL, startId, mergedColsV);
            m_Region.put(statusPut);
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: delete: STATELESS_UPDATE_OK");
            return STATELESS_UPDATE_OK;
        } else {
            // Return conflict, but don't trigger and abort.  That needs to be triggered from the client, if desired.
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: delete: STATELESS_UPDATE_CONFLICT");
            return STATELESS_UPDATE_CONFLICT;
        }
    }

    /***********************************************************************************
    *************************  Helper functions    ************************************
    ***********************************************************************************/
    public static int indexOf(byte[] source, byte[] find) {
        if (source == null) {
            return -1;
        }
        if (find == null) {
            return -1;
        }
        if (find.length > source.length) {
            return -1;
        }
        final int maxIndex = source.length - find.length;
        final int maxLength = find.length;
        final byte firstByte = find[0];
        int index = 0;
        Loop: do {
            if (source[index] == firstByte) {
                for (int i = 1; i < maxLength; i++) {
                    if (source[index + i] != find[i]) {
                        continue Loop;
                    }
                }
                return index;
            }
        } while (++index <= maxIndex);
        return -1;
    }

    public static byte[] byteMerger(byte[] byte_1, byte[] byte_2) {
        if (byte_1 == null) {
            if (byte_2 == null)
                return null;
            else
                return byte_2;
        } else {
            if (byte_2 == null)
                return byte_1;
        }

        byte[] byte_3 = new byte[byte_1.length + byte_2.length];
        System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length);
        System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length);
        return byte_3;
    }

    /** methods to handle the lookup table
    */

    /**
      generate a local transId and update the lookup table
    */
    /*    public void generateLocalId(SsccTransactionState state)
        {
    long localId = nextLocalTransId.getAndIncrement();
    state.setStartId(localId);
        }
    */
    public long getStartIdFromTs(long ts) {
        long id = 0;
        if (updateTsToStartId.containsKey(ts))
            id = updateTsToStartId.get(ts);
        return id;
    }

    public void mapStartIdFromTs(long ts, long id) {
        updateTsToStartId.put(ts, id);
    }

    /**
     * Retires the transaction
     * @param SsccTransactionState state
     */
    private void retireTransaction(final SsccTransactionState state) {
        //long key = state.getTransactionId();
        String key = getTransactionalUniqueId(state.getTransactionId());

        state.clearStateResource();

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: retireTransaction: [" + state.getTransactionId() + "]");

        try {
            transactionLeases.cancelLease(key);
        } catch (LeaseException le) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: retireTransaction: [" + state.getTransactionId()
                        + "] LeaseException");
            // Ignore
        } catch (Exception e) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: retireTransaction: [" + state.getTransactionId()
                        + "] General Lease exception");
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  Caught exception " + e.getMessage() + ""
                        + stackTraceToString(e));
            // Ignore
        }

        // Clearing transaction conflict check list in case it is holding
        // a reference to a transaction state

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  retireTransaction clearTransactionsById: " + key
                    + " from list");
        //state.clearTransactionsToCheck();

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  retireTransaction calling Removing transaction: " + key
                    + " from list");
        transactionsById.remove(key);
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  retireTransaction Removed transaction: " + key
                    + " from list");

    }

    @Override
    public void checkAndDelete(RpcController controller, SsccCheckAndDeleteRequest request,
            RpcCallback<SsccCheckAndDeleteResponse> done) {

        SsccCheckAndDeleteResponse response = SsccCheckAndDeleteResponse.getDefaultInstance();

        byte[] rowArray = null;
        com.google.protobuf.ByteString row = null;
        com.google.protobuf.ByteString family = null;
        com.google.protobuf.ByteString qualifier = null;
        com.google.protobuf.ByteString value = null;
        MutationProto proto = request.getDelete();
        MutationType type = proto.getMutateType();
        Delete delete = null;
        Throwable t = null;
        WrongRegionException wre = null;
        int status = 0;
        boolean result = false;
        long transId = request.getTransactionId();
        long startId = request.getStartId();

        java.lang.String name = ((com.google.protobuf.ByteString) request.getRegionName()).toStringUtf8();

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCheckAndDeleteResponse.Builder checkAndDeleteResponseBuilder = SsccCheckAndDeleteResponse
                .newBuilder();

        if (wre == null && type == MutationType.DELETE && proto.hasRow()) {
            rowArray = proto.getRow().toByteArray();

            try {
                delete = ProtobufUtil.toDelete(proto);
            } catch (Throwable e) {
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor: checkAndDelete caught exception " + e.getMessage()
                            + "" + stackTraceToString(e));
                t = e;
            }

            // Process in local memory
            if (delete != null && t == null) {
                if (request.hasRow()) {
                    row = request.getRow();

                    if (!Bytes.equals(rowArray, request.getRow().toByteArray()))
                        t = new org.apache.hadoop.hbase.DoNotRetryIOException(
                                "Action's " + "Delete row must match the passed row");
                }

                if (t == null) {
                    if (request.hasRow())
                        row = request.getRow();
                    if (request.hasFamily())
                        family = request.getFamily();
                    if (request.hasQualifier())
                        qualifier = request.getQualifier();
                    if (request.hasValue())
                        value = request.getValue();

                    try {
                        result = checkAndDelete(transId, startId, request.getRow().toByteArray(),
                                request.getFamily().toByteArray(), request.getQualifier().toByteArray(),
                                request.getValue().toByteArray(), delete);
                    } catch (Throwable e) {
                        if (LOG.isTraceEnabled())
                            LOG.trace("SsccRegionEndpoint coprocessor: checkAndDelete caught exception "
                                    + e.getMessage() + "" + stackTraceToString(e));
                        t = e;
                    }
                }

                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor: checkAndDelete setting result: " + result);
                checkAndDeleteResponseBuilder.setResult(result);
            }
        } else {
            result = false;
            checkAndDeleteResponseBuilder.setResult(result);
        }

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  checkAndDelete result is " + result);
        checkAndDeleteResponseBuilder.setHasException(false);

        if (t != null) {
            checkAndDeleteResponseBuilder.setHasException(true);
            checkAndDeleteResponseBuilder.setException(t.toString());
        }

        if (wre != null) {
            checkAndDeleteResponseBuilder.setHasException(true);
            checkAndDeleteResponseBuilder.setException(wre.toString());
        }

        SsccCheckAndDeleteResponse checkAndDeleteResponse = checkAndDeleteResponseBuilder.build();

        done.run(checkAndDeleteResponse);
    }

    @Override
    public void checkAndPut(RpcController controller, SsccCheckAndPutRequest request,
            RpcCallback<SsccCheckAndPutResponse> done) {

        SsccCheckAndPutResponse response = SsccCheckAndPutResponse.getDefaultInstance();

        byte[] rowArray = null;
        com.google.protobuf.ByteString row = null;
        com.google.protobuf.ByteString family = null;
        com.google.protobuf.ByteString qualifier = null;
        com.google.protobuf.ByteString value = null;
        MutationProto proto = request.getPut();
        MutationType type = proto.getMutateType();
        Put put = null;
        WrongRegionException wre = null;
        Throwable t = null;
        boolean result = false;
        long transId = request.getTransactionId();
        long startId = request.getStartId();

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccCheckAndPutResponse.Builder checkAndPutResponseBuilder = SsccCheckAndPutResponse
                .newBuilder();

        if (wre == null && type == MutationType.PUT && proto.hasRow()) {
            rowArray = proto.getRow().toByteArray();

            try {
                put = ProtobufUtil.toPut(proto);
            } catch (Throwable e) {
                LOG.error("SsccRegionEndpoint coprocessor: checkAndPut caught exception " + e.getMessage() + ""
                        + stackTraceToString(e));
                t = e;
            }

            // Process in local memory
            if (put != null) {
                if (request.hasRow()) {
                    row = request.getRow();

                    if (!Bytes.equals(rowArray, row.toByteArray())) {
                        t = new org.apache.hadoop.hbase.DoNotRetryIOException(
                                "Action's Put row must match the passed row");
                        if (LOG.isTraceEnabled())
                            LOG.trace(
                                    "SsccRegionEndpoint coprocessor: checkAndPut creating DoNotRetryIOException: setting result: Put row must match the passed row\n"
                                            + "rowArray: " + Bytes.toStringBinary(rowArray) + ", rowArray in hex: "
                                            + Hex.encodeHexString(rowArray) + ", row: "
                                            + Bytes.toStringBinary(request.getRow().toByteArray())
                                            + ", row in hex: "
                                            + Hex.encodeHexString(request.getRow().toByteArray()));
                    }
                }

                if (t == null) {
                    if (request.hasRow())
                        row = request.getRow();
                    if (request.hasFamily())
                        family = request.getFamily();
                    if (request.hasQualifier())
                        qualifier = request.getQualifier();
                    if (request.hasValue())
                        value = request.getValue();

                    try {
                        if (LOG.isTraceEnabled())
                            LOG.trace("SsccRegionEndpoint coprocessor: attempting checkAndPut for trans: " + transId
                                    + " startid: " + startId);
                        result = checkAndPut(transId, startId, request.getRow().toByteArray(),
                                request.getFamily().toByteArray(), request.getQualifier().toByteArray(),
                                request.getValue().toByteArray(), put);
                        if (LOG.isTraceEnabled())
                            LOG.trace("SsccRegionEndpoint coprocessor: checkAndPut returned " + result);
                    } catch (Throwable e) {
                        if (LOG.isTraceEnabled())
                            LOG.trace(
                                    "SsccRegionEndpoint coprocessor: checkAndPut threw exception after internal checkAndPut");
                        if (LOG.isTraceEnabled())
                            LOG.trace("SsccRegionEndpoint coprocessor: checkAnd Put caught exception "
                                    + e.getMessage() + "" + stackTraceToString(e));
                        t = e;
                    }
                }
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor: checkAndPut setting result: " + result);
                checkAndPutResponseBuilder.setResult(result);
            }
        } else {
            result = false;
            checkAndPutResponseBuilder.setResult(result);
        }

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  checkAndPut result is " + result);

        checkAndPutResponseBuilder.setHasException(false);

        if (wre != null) {
            checkAndPutResponseBuilder.setHasException(true);
            checkAndPutResponseBuilder.setException(wre.toString());
        }

        if (t != null) {
            checkAndPutResponseBuilder.setHasException(true);
            checkAndPutResponseBuilder.setException(t.toString());
        }

        SsccCheckAndPutResponse checkAndPutResponse = checkAndPutResponseBuilder.build();

        done.run(checkAndPutResponse);
    }

    /**
     * Processes a transactional checkAndDelete
     * @param long transactionId
     * @param byte[] row
     * @param byte[] family
     * @param byte[] qualifier
     * @param byte[] value
     * @param Delete delete
     * @return boolean
     * @throws IOException
     */
    public boolean checkAndDelete(long transactionId, long startId, byte[] row, byte[] family, byte[] qualifier,
            byte[] value, Delete delete) throws IOException {

        if (LOG.isTraceEnabled())
            LOG.trace("Enter SsccRegionEndpoint coprocessor: checkAndDelete, txid: " + transactionId);
        SsccTransactionState state = this.beginTransIfNotExist(transactionId, startId);
        boolean result = false;
        byte[] rsValue = null;

        Get get = new Get(row);
        get.addColumn(family, qualifier);

        Result rs = this.get(transactionId, startId, get);

        boolean valueIsNull = value == null || value.length == 0;
        int lv_return = 0;

        if (rs.isEmpty() && valueIsNull) {
            lv_return = this.delete(transactionId, startId, delete);
            result = (lv_return == STATELESS_UPDATE_OK) ? true : false;
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: checkAndDelete, txid: " + transactionId
                        + " rsValue.length == 0, lv_return: " + lv_return + ", result is " + result);

        } else if (!rs.isEmpty() && valueIsNull) {
            rsValue = rs.getValue(family, qualifier);
            if (rsValue != null && rsValue.length == 0) {
                lv_return = this.delete(transactionId, startId, delete);
                result = (lv_return == STATELESS_UPDATE_OK) ? true : false;
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor: checkAndDelete, txid: " + transactionId
                            + " rsValue.length == 0, lv_return: " + lv_return + ", result is: " + result);
            } else {
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor: checkAndDelete, txid: " + transactionId
                            + " rsValue.length != 0, result is false");
                result = false;
            }
        } else if ((!rs.isEmpty()) && !valueIsNull && (Bytes.equals(rs.getValue(family, qualifier), value))) {
            lv_return = this.delete(transactionId, startId, delete);
            result = (lv_return == STATELESS_UPDATE_OK) ? true : false;
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: checkAndDelete, txid: " + transactionId
                        + " rsValue matches the row, lv_return is: " + lv_return + ", result is: " + result);
        } else {
            result = false;
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: checkAndDelete  setting result is " + result + " row: "
                        + row);
        }

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: checkAndDelete  EXIT result is " + result + " row: " + row);

        return result;
    }

    /**
     * Processes a transactional checkAndPut
     * @param long transactionId
     * @param byte[] row
     * @param byte[] family
     * @param byte[] qualifier
     * @param byte[] value
     * @param Put put
     * @return boolean
     * @throws IOException
     */
    public boolean checkAndPut(long transactionId, long startId, byte[] row, byte[] family, byte[] qualifier,
            byte[] value, Put put) throws IOException {

        SsccTransactionState state = this.beginTransIfNotExist(transactionId, startId);
        boolean result = false;
        byte[] rsValue = null;

        Get get = new Get(row);
        get.addColumn(family, qualifier);
        if (LOG.isTraceEnabled())
            LOG.trace("Enter SsccRegionEndpoint coprocessor: checkAndPut, txid: " + transactionId + ", startId: "
                    + startId + ", row " + row);

        Result rs = this.get(transactionId, startId, get);

        if (LOG.isTraceEnabled())
            LOG.trace("Enter SsccRegionEndpoint coprocessor: checkAndPut, txid: " + transactionId
                    + ", result is empty " + rs.isEmpty() + ", value is " + Bytes.toString(value));

        boolean valueIsNull = value == null || value.length == 0;
        int lv_return = 0;
        if (rs.isEmpty() && valueIsNull) {
            lv_return = this.put(transactionId, startId, put, false /* stateful */);
            result = (lv_return == STATEFUL_UPDATE_OK) ? true : false;
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: checkAndPut, txid: " + transactionId
                        + " valueIsNull, lv_return is: " + lv_return + ", result is: " + result);
        } else if (!rs.isEmpty() && valueIsNull) {
            rsValue = rs.getValue(family, qualifier);
            if (rsValue != null && rsValue.length == 0) {
                lv_return = this.put(transactionId, startId, put, false /* stateful */);
                result = (lv_return == STATEFUL_UPDATE_OK) ? true : false;
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor: checkAndPut, txid: " + transactionId
                            + " rsValue.length == 0, lv_return: " + lv_return + ", result is: " + result);
            } else {
                result = false;
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor: checkAndPut, txid: " + transactionId
                            + " rsValue.length != 0, result is false");
            }
        } else if ((!rs.isEmpty()) && !valueIsNull && (Bytes.equals(rs.getValue(family, qualifier), value))) {
            lv_return = this.put(transactionId, startId, put, false /* stateful */);
            result = (lv_return == STATEFUL_UPDATE_OK) ? true : false;
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: checkAndPut, txid: " + transactionId
                        + " rsValue matches the row, lv_return is: " + lv_return + ", result is: " + result);

        } else {
            result = false;
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: checkAndPut, txid: " + transactionId
                        + " last case, result is false");
        }

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  checkAndPut returns " + result + " for row: " + row);

        return result;
    }

    @Override
    public void deleteMultiple(RpcController controller, SsccDeleteMultipleTransactionalRequest request,
            RpcCallback<SsccDeleteMultipleTransactionalResponse> done) {
        SsccDeleteMultipleTransactionalResponse response = SsccDeleteMultipleTransactionalResponse
                .getDefaultInstance();

        java.util.List<org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto> results;
        results = request.getDeleteList();
        int resultCount = request.getDeleteCount();
        byte[] row = null;
        Delete delete = null;
        MutationType type;
        Throwable t = null;
        WrongRegionException wre = null;
        int status = 0;
        long transId = request.getTransactionId();
        long startId = request.getStartId();

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor deleteMultiple: Entry");

        if (wre == null) {
            for (org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto proto : results) {
                delete = null;

                if (proto != null) {
                    type = proto.getMutateType();

                    if (type == MutationType.DELETE && proto.hasRow()) {
                        row = proto.getRow().toByteArray();

                        try {
                            delete = ProtobufUtil.toDelete(proto);
                        } catch (Throwable e) {
                            if (LOG.isTraceEnabled())
                                LOG.trace("SsccRegionEndpoint coprocessor deleteMultiple:delete Caught exception "
                                        + "after protobuf conversion " + e.getMessage() + ""
                                        + stackTraceToString(e));
                            t = e;
                        }

                        // Process in local memory
                        if (delete != null) {
                            try {
                                status = delete(transId, startId, delete);
                            } catch (Throwable e) {
                                if (LOG.isTraceEnabled())
                                    LOG.trace(
                                            "SsccRegionEndpoint coprocessor deleteMultiple:delete Caught exception "
                                                    + "after internal delete " + e.getMessage() + ""
                                                    + stackTraceToString(e));
                                t = e;
                            }

                            if (LOG.isTraceEnabled())
                                LOG.trace("SsccRegionEndpoint coprocessor: deleteMultiple - id " + transId
                                        + ", regionName " + regionInfo.getRegionNameAsString() + ", type " + type
                                        + ", row " + Bytes.toString(row));

                            if (status != STATELESS_UPDATE_OK) {
                                String returnString;

                                switch (status) {
                                case STATEFUL_UPDATE_OK:
                                    returnString = new String("STATEFUL_UPDATE_OK");
                                    break;
                                case STATEFUL_UPDATE_CONFLICT:
                                    returnString = new String("STATEFUL_UPDATE_CONFLICT");
                                    break;
                                case STATELESS_UPDATE_OK:
                                    returnString = new String("STATELESS_UPDATE_OK");
                                    break;
                                case STATELESS_UPDATE_CONFLICT:
                                    returnString = new String("STATELESS_UPDATE_CONFLICT");
                                    break;
                                default:
                                    returnString = new String("Unknown return value: " + Integer.toString(status));
                                    break;
                                }
                                if (LOG.isTraceEnabled())
                                    LOG.trace("SsccRegionEndpoint coprocessor:deleteMultiple returned status: "
                                            + returnString);
                                break;
                            }

                        }
                    }
                } else if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor: deleteMultiple - id " + transId + ", regionName "
                            + regionInfo.getRegionNameAsString() + ", delete proto was null");

            }
        }

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccDeleteMultipleTransactionalResponse.Builder deleteMultipleTransactionalResponseBuilder = SsccDeleteMultipleTransactionalResponse
                .newBuilder();

        deleteMultipleTransactionalResponseBuilder.setHasException(false);

        if (t != null) {
            deleteMultipleTransactionalResponseBuilder.setHasException(true);
            deleteMultipleTransactionalResponseBuilder.setException(t.toString());
        }

        if (wre != null) {
            deleteMultipleTransactionalResponseBuilder.setHasException(true);
            deleteMultipleTransactionalResponseBuilder.setException(wre.toString());
        }

        deleteMultipleTransactionalResponseBuilder.setStatus(status);
        SsccDeleteMultipleTransactionalResponse dresponse = deleteMultipleTransactionalResponseBuilder.build();

        done.run(dresponse);
    }

    @Override
    public void putMultiple(RpcController controller, SsccPutMultipleTransactionalRequest request,
            RpcCallback<SsccPutMultipleTransactionalResponse> done) {
        SsccPutMultipleTransactionalResponse response = SsccPutMultipleTransactionalResponse.getDefaultInstance();

        java.util.List<org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto> results;

        boolean stateless = false;
        if (request.hasIsStateless()) {
            stateless = request.getIsStateless();
        }
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor putMultiple: Entry, stateless: " + stateless);

        results = request.getPutList();
        int resultCount = request.getPutCount();
        byte[] row = null;
        Put put = null;
        MutationType type;
        Throwable t = null;
        WrongRegionException wre = null;
        int status = 0;
        long transId = request.getTransactionId();
        long startId = request.getStartId();

        if (wre == null) {

            for (org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto proto : results) {
                put = null;

                if (proto != null) {
                    type = proto.getMutateType();

                    if (type == MutationType.PUT && proto.hasRow()) {
                        row = proto.getRow().toByteArray();

                        try {
                            if (LOG.isTraceEnabled())
                                LOG.trace("SsccRegionEndpoint coprocessor putMultiple: converting put");
                            put = ProtobufUtil.toPut(proto);
                        } catch (Throwable e) {
                            if (LOG.isTraceEnabled())
                                LOG.trace("SsccRegionEndpoint coprocessor putMultiple:put Caught exception "
                                        + "after protobuf conversion " + e.getMessage() + ""
                                        + stackTraceToString(e));
                            t = e;
                        }

                        // Process in local memory
                        if (put != null) {
                            try {
                                status = put(transId, startId, put, stateless);
                                if (LOG.isTraceEnabled())
                                    LOG.trace("SsccRegionEndpoint coprocessor:putMultiple returned status: "
                                            + status);
                            } catch (Throwable e) {
                                if (LOG.isTraceEnabled())
                                    LOG.trace("SsccRegionEndpoint coprocessor putMultiple:put Caught exception "
                                            + "after internal put " + e.getMessage() + "" + stackTraceToString(e));
                                t = e;
                            }

                            if (LOG.isTraceEnabled())
                                LOG.trace("SsccRegionEndpoint coprocessor: putMultiple - id " + transId
                                        + ", regionName " + regionInfo.getRegionNameAsString() + ", type " + type
                                        + ", row " + Bytes.toString(row));
                        } else {
                            if (LOG.isTraceEnabled())
                                LOG.trace("SsccRegionEndpoint coprocessor: putMultiple - put is null ");
                        }
                        if (status != STATEFUL_UPDATE_OK) {
                            String returnString;

                            switch (status) {
                            case STATEFUL_UPDATE_OK:
                                returnString = new String("STATEFUL_UPDATE_OK");
                                break;
                            case STATEFUL_UPDATE_CONFLICT:
                                returnString = new String("STATEFUL_UPDATE_CONFLICT");
                                break;
                            case STATELESS_UPDATE_OK:
                                returnString = new String("STATELESS_UPDATE_OK");
                                break;
                            case STATELESS_UPDATE_CONFLICT:
                                returnString = new String("STATELESS_UPDATE_CONFLICT");
                                break;
                            default:
                                returnString = new String("Unknown return value: " + Integer.toString(status));
                                break;
                            }
                            if (LOG.isTraceEnabled())
                                LOG.trace("SsccRegionEndpoint coprocessor:putMultiple returned status: "
                                        + returnString);
                            break;
                        }
                    }
                } else if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor: putMultiple - id " + transId + ", regionName "
                            + regionInfo.getRegionNameAsString() + ", proto was null");

            }
        }

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccPutMultipleTransactionalResponse.Builder putMultipleTransactionalResponseBuilder = SsccPutMultipleTransactionalResponse
                .newBuilder();

        putMultipleTransactionalResponseBuilder.setHasException(false);

        if (t != null) {
            putMultipleTransactionalResponseBuilder.setHasException(true);
            putMultipleTransactionalResponseBuilder.setException(t.toString());
        }

        if (wre != null) {
            putMultipleTransactionalResponseBuilder.setHasException(true);
            putMultipleTransactionalResponseBuilder.setException(wre.toString());
        }

        putMultipleTransactionalResponseBuilder.setStatus(status);
        SsccPutMultipleTransactionalResponse pmresponse = putMultipleTransactionalResponseBuilder.build();
        done.run(pmresponse);
    }

    //****************************************************************
    //
    //  ANYTHING ABOVE THIS LINE HAS BEEN CONVERTED FOR SSCC
    //
    //  ANYTHING BELOW THIS COMMENT HAS NOT BEEN CONVERTED FOR SSCC
    //  AND IS LEFT HERE FOR REFERENCE ONLY.  WILL BE REMOVED AFTER POC
    //
    //****************************************************************

    // TrxRegionService methods

    @Override
    public void recoveryRequest(RpcController controller, SsccRecoveryRequestRequest request,
            RpcCallback<SsccRecoveryRequestResponse> done) {
        int tmId = request.getTmId();
        Throwable t = null;
        WrongRegionException wre = null;
        long transId = request.getTransactionId();
        long startId = request.getStartId();

        if (reconstructIndoubts == 0) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  RECOV recovery Request");
            //         try {
            constructIndoubtTransactions();
            //         }
            //         catch (IdTmException e){
            //            LOG.error("SsccRegionEndpoint coprocessor:  RECOV recovery Request exception " + e);
            //            t = new IOException("SsccRegionEndpoint coprocessor:  RECOV recovery Request exception " + e);
            //         }
            //         catch (Exception e2){
            //            LOG.error("SsccRegionEndpoint coprocessor:  RECOV recovery Request exception " + e2);
            //            t = new IOException("SsccRegionEndpoint coprocessor:  RECOV recovery Request exception " + e2);
            //         }

        }

        // Placeholder for real work when recovery is added
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: recoveryResponse - id " + transId + ", regionName "
                    + regionInfo.getRegionNameAsString() + ", tmId" + tmId);

        org.apache.hadoop.hbase.coprocessor.transactional.generated.SsccRegionProtos.SsccRecoveryRequestResponse.Builder recoveryResponseBuilder = SsccRecoveryRequestResponse
                .newBuilder();

        List<Long> indoubtTransactions = new ArrayList<Long>();
        if (LOG.isTraceEnabled())
            LOG.trace("Trafodion Recovery: region " + regionInfo.getEncodedName()
                    + " receives recovery request from TM " + tmId + " with region state " + regionState);
        switch (regionState) {
        case 1: // INIT, assume open the TRegion if necessary
            regionState = 1; //Note. ??? should we call openHRegion directly here
            break;
        case 0: // RECOVERING, already create a list of in-doubt txn, but still in the state of resolving them,
                // retrieve all in-doubt txn from rmid and return them into a long a
            for (Entry<Long, WALEdit> entry : indoubtTransactionsById.entrySet()) {
                long tid = entry.getKey();
                if ((int) (tid >> 32) == tmId) {
                    indoubtTransactions.add(tid);
                    if (LOG.isTraceEnabled())
                        LOG.trace("Trafodion Recovery: region " + regionInfo.getEncodedName()
                                + " in-doubt transaction " + tid + " has been added into the recovery repply to TM "
                                + tmId);
                }
            }
            break;
        case 2: // START
            break;
        }

        // Placeholder response forced to zero for now
        for (Long transactionId : indoubtTransactions) {
            recoveryResponseBuilder.addResult(transactionId);
        }
        // Placeholder response forced to zero for now

        recoveryResponseBuilder.setHasException(false);

        if (t != null) {
            recoveryResponseBuilder.setHasException(true);
            recoveryResponseBuilder.setException(t.toString());
        }

        if (wre != null) {
            recoveryResponseBuilder.setHasException(true);
            recoveryResponseBuilder.setException(wre.toString());
        }

        SsccRecoveryRequestResponse rresponse = recoveryResponseBuilder.build();
        done.run(rresponse);
    }

    /**
     * Gives the maximum for a given combination of column qualifier and column
     * family, in the given row range as defined in the Scan object. In its
     * current implementation, it takes one column family and one column qualifier
     * (if provided). In case of null column qualifier, maximum value for the
     * entire column family will be returned.
     */
    @Override
    public void getMax(RpcController controller, SsccTransactionalAggregateRequest request,
            RpcCallback<SsccTransactionalAggregateResponse> done) {
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: getMax entry");
        RegionScanner scanner = null;
        SsccTransactionalAggregateResponse response = null;
        T max = null;
        try {
            ColumnInterpreter<T, S, P, Q, R> ci = constructColumnInterpreterFromRequest(request);
            T temp;
            long transactionId = request.getTransactionId();
            long startId = request.getStartId();
            Scan scan = ProtobufUtil.toScan(request.getScan());
            scanner = getScanner(transactionId, startId, scan);
            List<Cell> results = new ArrayList<Cell>();
            byte[] colFamily = scan.getFamilies()[0];
            NavigableSet<byte[]> qualifiers = scan.getFamilyMap().get(colFamily);
            byte[] qualifier = null;
            if (qualifiers != null && !qualifiers.isEmpty()) {
                qualifier = qualifiers.pollFirst();
            }
            // qualifier can be null.
            boolean hasMoreRows = false;
            do {
                hasMoreRows = scanner.next(results);
                for (Cell kv : results) {
                    temp = ci.getValue(colFamily, qualifier, kv);
                    max = (max == null || (temp != null && ci.compare(temp, max) > 0)) ? temp : max;
                }
                results.clear();
            } while (hasMoreRows);
            if (max != null) {
                SsccTransactionalAggregateResponse.Builder builder = SsccTransactionalAggregateResponse
                        .newBuilder();
                builder.addFirstPart(ci.getProtoForCellType(max).toByteString());
                response = builder.build();
            }
        } catch (IOException e) {
            ResponseConverter.setControllerException(controller, e);
        } finally {
            if (scanner != null) {
                try {
                    scanner.close();
                } catch (IOException ignored) {
                }
            }
        }
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: getMax - Maximum from this region is "
                    + env.getRegion().getRegionNameAsString() + ": " + max);
        done.run(response);
    }

    /**
     * Gives the minimum for a given combination of column qualifier and column
     * family, in the given row range as defined in the Scan object. In its
     * current implementation, it takes one column family and one column qualifier
     * (if provided). In case of null column qualifier, minimum value for the
     * entire column family will be returned.
     */
    @Override
    public void getMin(RpcController controller, SsccTransactionalAggregateRequest request,
            RpcCallback<SsccTransactionalAggregateResponse> done) {
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: getMin entry");
        SsccTransactionalAggregateResponse response = null;
        RegionScanner scanner = null;
        T min = null;
        try {
            ColumnInterpreter<T, S, P, Q, R> ci = constructColumnInterpreterFromRequest(request);
            T temp;
            Scan scan = ProtobufUtil.toScan(request.getScan());
            long transactionId = request.getTransactionId();
            long startId = request.getStartId();
            scanner = getScanner(transactionId, startId, scan);
            List<Cell> results = new ArrayList<Cell>();
            byte[] colFamily = scan.getFamilies()[0];
            NavigableSet<byte[]> qualifiers = scan.getFamilyMap().get(colFamily);
            byte[] qualifier = null;
            if (qualifiers != null && !qualifiers.isEmpty()) {
                qualifier = qualifiers.pollFirst();
            }
            boolean hasMoreRows = false;
            do {
                hasMoreRows = scanner.next(results);
                for (Cell kv : results) {
                    temp = ci.getValue(colFamily, qualifier, kv);
                    min = (min == null || (temp != null && ci.compare(temp, min) < 0)) ? temp : min;
                }
                results.clear();
            } while (hasMoreRows);
            if (min != null) {
                response = SsccTransactionalAggregateResponse.newBuilder()
                        .addFirstPart(ci.getProtoForCellType(min).toByteString()).build();
            }
        } catch (IOException e) {
            ResponseConverter.setControllerException(controller, e);
        } finally {
            if (scanner != null) {
                try {
                    scanner.close();
                } catch (IOException ignored) {
                }
            }
        }
        if (LOG.isTraceEnabled())
            LOG.trace("Minimum from this region is " + env.getRegion().getRegionNameAsString() + ": " + min);
        done.run(response);
    }

    /**
     * Gives the sum for a given combination of column qualifier and column
     * family, in the given row range as defined in the Scan object. In its
     * current implementation, it takes one column family and one column qualifier
     * (if provided). In case of null column qualifier, sum for the entire column
     * family will be returned.
     */
    @Override
    public void getSum(RpcController controller, SsccTransactionalAggregateRequest request,
            RpcCallback<SsccTransactionalAggregateResponse> done) {
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: getSum entry");
        SsccTransactionalAggregateResponse response = null;
        RegionScanner scanner = null;
        long sum = 0L;
        try {
            ColumnInterpreter<T, S, P, Q, R> ci = constructColumnInterpreterFromRequest(request);
            S sumVal = null;
            T temp;
            Scan scan = ProtobufUtil.toScan(request.getScan());
            long transactionId = request.getTransactionId();
            long startId = request.getStartId();
            scanner = getScanner(transactionId, startId, scan);
            SsccTransactionState state = this.beginTransIfNotExist(transactionId, startId);
            byte[] colFamily = scan.getFamilies()[0];
            NavigableSet<byte[]> qualifiers = scan.getFamilyMap().get(colFamily);
            byte[] qualifier = null;
            if (qualifiers != null && !qualifiers.isEmpty()) {
                qualifier = qualifiers.pollFirst();
            }
            List<Cell> results = new ArrayList<Cell>();
            boolean hasMoreRows = false;
            boolean firstCell;
            do {
                hasMoreRows = scanner.next(results);
                firstCell = true;
                Result verResult = null;
                Result statusResult = null;
                Result colResult = null;
                for (Cell c : results) {
                    if (firstCell == true) {
                        if (CellUtil.cloneFamily(c) != DtmConst.TRANSACTION_META_FAMILY) {
                            //get the statusList
                            Get statusGet = new Get(c.getRow()); //TODO: deprecated API
                            if (LOG.isTraceEnabled())
                                LOG.trace("SsccRegionEndpoint coprocessor: getSum first row:  " + c.getRow());
                            //statusGet.setTimeStamp(startId);
                            statusGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.STATUS_COL);
                            statusGet.setMaxVersions(DtmConst.MAX_VERSION);
                            statusResult = m_Region.get(statusGet);

                            //get the colList
                            Get colGet = new Get(c.getRow()); //TODO: deprecated API
                            //colGet.setTimeStamp(startId);
                            colGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.COLUMNS_COL);
                            colGet.setMaxVersions(DtmConst.MAX_VERSION);
                            colResult = m_Region.get(colGet);

                            //get the versionList
                            Get verGet = new Get(c.getRow());//TODO: deprecated API
                            //verGet.setTimeStamp(startId);
                            verGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.VERSION_COL);
                            verGet.setMaxVersions(DtmConst.MAX_VERSION);
                            verResult = m_Region.get(verGet);
                            firstCell = false;
                        }

                        if (firstCell == false) {

                            temp = ci.getValue(colFamily, qualifier, c);
                            if (temp != null) {
                                if (state.handleResult(c, statusResult.listCells(), verResult.listCells(),
                                        colResult.listCells(), transactionId) == true) {
                                    if (LOG.isTraceEnabled())
                                        LOG.trace("SsccRegionEndpoint coprocessor: getSum adding cell: "
                                                + c.getRow());
                                    sumVal = ci.add(sumVal, ci.castToReturnType(temp));
                                    break;
                                }
                            }
                        }
                    }
                }
                results.clear();
            } while (hasMoreRows);
            if (sumVal != null) {
                response = SsccTransactionalAggregateResponse.newBuilder()
                        .addFirstPart(ci.getProtoForPromotedType(sumVal).toByteString()).build();
            }
        } catch (IOException e) {
            ResponseConverter.setControllerException(controller, e);
        } finally {
            if (scanner != null) {
                try {
                    scanner.close();
                } catch (IOException ignored) {
                }
            }
        }
        if (LOG.isTraceEnabled())
            LOG.trace("Sum from this region is " + env.getRegion().getRegionNameAsString() + ": " + sum);
        done.run(response);
    }

    /**
     * Gives the row count for the given column family and column qualifier, in
     * the given row range as defined in the Scan object.
     * @throws IOException
     */
    @Override
    public void getRowNum(RpcController controller, SsccTransactionalAggregateRequest request,
            RpcCallback<SsccTransactionalAggregateResponse> done) {
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: getRowNum entry");
        SsccTransactionalAggregateResponse response = null;
        long counter = 0L;
        List<Cell> results = new ArrayList<Cell>();
        RegionScanner scanner = null;
        long transactionId = 0L;
        try {
            Scan scan = ProtobufUtil.toScan(request.getScan());
            byte[][] colFamilies = scan.getFamilies();
            byte[] colFamily = colFamilies != null ? colFamilies[0] : null;
            NavigableSet<byte[]> qualifiers = colFamilies != null ? scan.getFamilyMap().get(colFamily) : null;
            byte[] qualifier = null;
            if (qualifiers != null && !qualifiers.isEmpty()) {
                qualifier = qualifiers.pollFirst();
            }
            if (scan.getFilter() == null && qualifier == null)
                scan.setFilter(new FirstKeyOnlyFilter());
            transactionId = request.getTransactionId();
            long startId = request.getStartId();
            scanner = getScanner(transactionId, startId, scan);
            SsccTransactionState state = this.beginTransIfNotExist(transactionId, startId);
            boolean hasMoreRows = false;
            boolean firstCell;
            do {
                hasMoreRows = scanner.next(results);
                firstCell = true;
                Result verResult = null;
                Result statusResult = null;
                Result colResult = null;
                for (Cell c : results) {
                    if (firstCell == true) {
                        if (CellUtil.cloneFamily(c) != DtmConst.TRANSACTION_META_FAMILY) {
                            //get the statusList
                            Get statusGet = new Get(c.getRow()); //TODO: deprecated API
                            if (LOG.isTraceEnabled())
                                LOG.trace("SsccRegionEndpoint coprocessor: getRowNum first row:  " + c.getRow());
                            //statusGet.setTimeStamp(startId);
                            statusGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.STATUS_COL);
                            statusGet.setMaxVersions(DtmConst.MAX_VERSION);
                            statusResult = m_Region.get(statusGet);

                            //get the colList
                            Get colGet = new Get(c.getRow()); //TODO: deprecated API
                            //colGet.setTimeStamp(startId);
                            colGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.COLUMNS_COL);
                            colGet.setMaxVersions(DtmConst.MAX_VERSION);
                            colResult = m_Region.get(colGet);

                            //get the versionList
                            Get verGet = new Get(c.getRow());//TODO: deprecated API
                            //verGet.setTimeStamp(startId);
                            verGet.addColumn(DtmConst.TRANSACTION_META_FAMILY, SsccConst.VERSION_COL);
                            verGet.setMaxVersions(DtmConst.MAX_VERSION);
                            verResult = m_Region.get(verGet);
                            firstCell = false;
                        }

                        if (firstCell == false) {
                            if (state.handleResult(c, statusResult.listCells(), verResult.listCells(),
                                    colResult.listCells(), transactionId) == true) {
                                if (LOG.isTraceEnabled())
                                    LOG.trace(
                                            "SsccRegionEndpoint coprocessor: getRowNum adding cell: " + c.getRow());
                                counter++;
                                break;
                            }
                        }
                    }
                }
                results.clear();
            } while (hasMoreRows);
            ByteBuffer bb = ByteBuffer.allocate(8).putLong(counter);
            bb.rewind();
            response = SsccTransactionalAggregateResponse.newBuilder().addFirstPart(ByteString.copyFrom(bb))
                    .build();
        } catch (IOException e) {
            ResponseConverter.setControllerException(controller, e);
        } finally {
            if (scanner != null) {
                try {
                    scanner.close();
                } catch (IOException ignored) {
                }
            }
        }
        if (LOG.isTraceEnabled())
            LOG.trace("Row counter for transactionId " + transactionId + " from this region: "
                    + env.getRegion().getRegionNameAsString() + " is " + counter);
        done.run(response);
    }

    /**
     * Gives a Pair with first object as Sum and second object as row count,
     * computed for a given combination of column qualifier and column family in
     * the given row range as defined in the Scan object. In its current
     * implementation, it takes one column family and one column qualifier (if
     * provided). In case of null column qualifier, an aggregate sum over all the
     * entire column family will be returned.
     * <p>
     * The average is computed in
     * AggregationClient#avg(byte[], ColumnInterpreter, Scan) by
     * processing results from all regions, so its "ok" to pass sum and a Long
     * type.
     */
    @Override
    public void getAvg(RpcController controller, SsccTransactionalAggregateRequest request,
            RpcCallback<SsccTransactionalAggregateResponse> done) {
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: getAvg entry");
        SsccTransactionalAggregateResponse response = null;
        RegionScanner scanner = null;
        try {
            ColumnInterpreter<T, S, P, Q, R> ci = constructColumnInterpreterFromRequest(request);
            S sumVal = null;
            Long rowCountVal = 0L;
            Scan scan = ProtobufUtil.toScan(request.getScan());
            long transactionId = request.getTransactionId();
            long startId = request.getStartId();
            scanner = getScanner(transactionId, startId, scan);
            byte[] colFamily = scan.getFamilies()[0];
            NavigableSet<byte[]> qualifiers = scan.getFamilyMap().get(colFamily);
            byte[] qualifier = null;
            if (qualifiers != null && !qualifiers.isEmpty()) {
                qualifier = qualifiers.pollFirst();
            }
            List<Cell> results = new ArrayList<Cell>();
            boolean hasMoreRows = false;

            do {
                results.clear();
                hasMoreRows = scanner.next(results);
                for (Cell kv : results) {
                    sumVal = ci.add(sumVal, ci.castToReturnType(ci.getValue(colFamily, qualifier, kv)));
                }
                rowCountVal++;
            } while (hasMoreRows);
            if (sumVal != null) {
                ByteString first = ci.getProtoForPromotedType(sumVal).toByteString();
                SsccTransactionalAggregateResponse.Builder pair = SsccTransactionalAggregateResponse.newBuilder();
                pair.addFirstPart(first);
                ByteBuffer bb = ByteBuffer.allocate(8).putLong(rowCountVal);
                bb.rewind();
                pair.setSecondPart(ByteString.copyFrom(bb));
                response = pair.build();
            }
        } catch (IOException e) {
            ResponseConverter.setControllerException(controller, e);
        } finally {
            if (scanner != null) {
                try {
                    scanner.close();
                } catch (IOException ignored) {
                }
            }
        }
        done.run(response);
    }

    /**
     * Gives a Pair with first object a List containing Sum and sum of squares,
     * and the second object as row count. It is computed for a given combination of
     * column qualifier and column family in the given row range as defined in the
     * Scan object. In its current implementation, it takes one column family and
     * one column qualifier (if provided). The idea is get the value of variance first:
     * the average of the squares less the square of the average a standard
     * deviation is square root of variance.
     */
    @Override
    public void getStd(RpcController controller, SsccTransactionalAggregateRequest request,
            RpcCallback<SsccTransactionalAggregateResponse> done) {
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: getStd entry");
        RegionScanner scanner = null;
        SsccTransactionalAggregateResponse response = null;
        try {
            ColumnInterpreter<T, S, P, Q, R> ci = constructColumnInterpreterFromRequest(request);
            S sumVal = null, sumSqVal = null, tempVal = null;
            long rowCountVal = 0L;
            Scan scan = ProtobufUtil.toScan(request.getScan());
            long transactionId = request.getTransactionId();
            long startId = request.getStartId();
            scanner = getScanner(transactionId, startId, scan);
            byte[] colFamily = scan.getFamilies()[0];
            NavigableSet<byte[]> qualifiers = scan.getFamilyMap().get(colFamily);
            byte[] qualifier = null;
            if (qualifiers != null && !qualifiers.isEmpty()) {
                qualifier = qualifiers.pollFirst();
            }
            List<Cell> results = new ArrayList<Cell>();

            boolean hasMoreRows = false;

            do {
                tempVal = null;
                hasMoreRows = scanner.next(results);
                for (Cell kv : results) {
                    tempVal = ci.add(tempVal, ci.castToReturnType(ci.getValue(colFamily, qualifier, kv)));
                }
                results.clear();
                sumVal = ci.add(sumVal, tempVal);
                sumSqVal = ci.add(sumSqVal, ci.multiply(tempVal, tempVal));
                rowCountVal++;
            } while (hasMoreRows);
            if (sumVal != null) {
                ByteString first_sumVal = ci.getProtoForPromotedType(sumVal).toByteString();
                ByteString first_sumSqVal = ci.getProtoForPromotedType(sumSqVal).toByteString();
                SsccTransactionalAggregateResponse.Builder pair = SsccTransactionalAggregateResponse.newBuilder();
                pair.addFirstPart(first_sumVal);
                pair.addFirstPart(first_sumSqVal);
                ByteBuffer bb = ByteBuffer.allocate(8).putLong(rowCountVal);
                bb.rewind();
                pair.setSecondPart(ByteString.copyFrom(bb));
                response = pair.build();
            }
        } catch (IOException e) {
            ResponseConverter.setControllerException(controller, e);
        } finally {
            if (scanner != null) {
                try {
                    scanner.close();
                } catch (IOException ignored) {
                }
            }
        }
        done.run(response);
    }

    /**
     * Gives a List containing sum of values and sum of weights.
     * It is computed for the combination of column
     * family and column qualifier(s) in the given row range as defined in the
     * Scan object. In its current implementation, it takes one column family and
     * two column qualifiers. The first qualifier is for values column and 
     * the second qualifier (optional) is for weight column.
     */
    @Override
    public void getMedian(RpcController controller, SsccTransactionalAggregateRequest request,
            RpcCallback<SsccTransactionalAggregateResponse> done) {
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: getMedian entry");
        SsccTransactionalAggregateResponse response = null;
        RegionScanner scanner = null;
        try {
            ColumnInterpreter<T, S, P, Q, R> ci = constructColumnInterpreterFromRequest(request);
            S sumVal = null, sumWeights = null, tempVal = null, tempWeight = null;
            Scan scan = ProtobufUtil.toScan(request.getScan());
            long transactionId = request.getTransactionId();
            long startId = request.getStartId();
            scanner = getScanner(transactionId, startId, scan);
            byte[] colFamily = scan.getFamilies()[0];
            NavigableSet<byte[]> qualifiers = scan.getFamilyMap().get(colFamily);
            byte[] valQualifier = null, weightQualifier = null;
            if (qualifiers != null && !qualifiers.isEmpty()) {
                valQualifier = qualifiers.pollFirst();
                // if weighted median is requested, get qualifier for the weight column
                weightQualifier = qualifiers.pollLast();
            }
            List<Cell> results = new ArrayList<Cell>();

            boolean hasMoreRows = false;

            do {
                tempVal = null;
                tempWeight = null;
                hasMoreRows = scanner.next(results);
                for (Cell kv : results) {
                    tempVal = ci.add(tempVal, ci.castToReturnType(ci.getValue(colFamily, valQualifier, kv)));
                    if (weightQualifier != null) {
                        tempWeight = ci.add(tempWeight,
                                ci.castToReturnType(ci.getValue(colFamily, weightQualifier, kv)));
                    }
                }
                results.clear();
                sumVal = ci.add(sumVal, tempVal);
                sumWeights = ci.add(sumWeights, tempWeight);
            } while (hasMoreRows);
            ByteString first_sumVal = ci.getProtoForPromotedType(sumVal).toByteString();
            S s = sumWeights == null ? ci.castToReturnType(ci.getMinValue()) : sumWeights;
            ByteString first_sumWeights = ci.getProtoForPromotedType(s).toByteString();
            SsccTransactionalAggregateResponse.Builder pair = SsccTransactionalAggregateResponse.newBuilder();
            pair.addFirstPart(first_sumVal);
            pair.addFirstPart(first_sumWeights);
            response = pair.build();
        } catch (IOException e) {
            ResponseConverter.setControllerException(controller, e);
        } finally {
            if (scanner != null) {
                try {
                    scanner.close();
                } catch (IOException ignored) {
                }
            }
        }
        done.run(response);
    }

    @SuppressWarnings("unchecked")
    ColumnInterpreter<T, S, P, Q, R> constructColumnInterpreterFromRequest(
            SsccTransactionalAggregateRequest request) throws IOException {
        String className = request.getInterpreterClassName();
        Class<?> cls;
        try {
            cls = Class.forName(className);
            ColumnInterpreter<T, S, P, Q, R> ci = (ColumnInterpreter<T, S, P, Q, R>) cls.newInstance();
            if (request.hasInterpreterSpecificBytes()) {
                ByteString b = request.getInterpreterSpecificBytes();
                P initMsg = ProtobufUtil.getParsedGenericInstance(ci.getClass(), 2, b);
                ci.initialize(initMsg);
            }
            return ci;
        } catch (ClassNotFoundException e) {
            throw new IOException(e);
        } catch (InstantiationException e) {
            throw new IOException(e);
        } catch (IllegalAccessException e) {
            throw new IOException(e);
        }
    }

    @Override
    public Service getService() {
        return this;
    }

    /**
     * Stores a reference to the coprocessor environment provided by the
     * {@link org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost} 
     * from the region where this coprocessor is loaded.
     * Since this is a coprocessor endpoint, it always expects to be loaded
     * on a table region, so always expects this to be an instance of
     * {@link RegionCoprocessorEnvironment}.
     * @param env the environment provided by the coprocessor host
     * @throws IOException if the provided environment is not an instance of
     * {@code RegionCoprocessorEnvironment}
     */
    @Override
    public void start(CoprocessorEnvironment env) throws IOException {
        if (env instanceof RegionCoprocessorEnvironment) {
            this.env = (RegionCoprocessorEnvironment) env;
        } else {
            throw new CoprocessorException(
                    "SsccRegionEndpoint coprocessor: start - Must be loaded on a table region!");
        }
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: start");
        RegionCoprocessorEnvironment tmp_env = (RegionCoprocessorEnvironment) env;
        this.m_Region = tmp_env.getRegion();
        this.regionInfo = this.m_Region.getRegionInfo();
        this.t_Region = (TransactionalRegion) tmp_env.getRegion();
        this.fs = this.m_Region.getFilesystem();

        org.apache.hadoop.conf.Configuration conf = new org.apache.hadoop.conf.Configuration();

        synchronized (stoppableLock) {
            try {
                this.transactionLeaseTimeout = HBaseConfiguration.getInt(conf,
                        HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD,
                        HConstants.HBASE_REGIONSERVER_LEASE_PERIOD_KEY, DEFAULT_LEASE_TIME);

                this.scannerLeaseTimeoutPeriod = HBaseConfiguration.getInt(conf,
                        HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD,
                        HConstants.HBASE_REGIONSERVER_LEASE_PERIOD_KEY,
                        HConstants.DEFAULT_HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD);

                scannerThreadWakeFrequency = conf.getInt(HConstants.THREAD_WAKE_FREQUENCY, 10 * 1000);

                this.cleanTimer = conf.getInt(SLEEP_CONF, DEFAULT_SLEEP);

                if (this.transactionLeases == null)
                    this.transactionLeases = new Leases(LEASE_CHECK_FREQUENCY);

                if (LOG.isTraceEnabled())
                    LOG.trace("Transaction lease time: " + transactionLeaseTimeout);
                if (LOG.isTraceEnabled())
                    LOG.trace("Scanner lease time: " + scannerThreadWakeFrequency);

                UncaughtExceptionHandler handler = new UncaughtExceptionHandler() {

                    public void uncaughtException(final Thread t, final Throwable e) {
                        LOG.fatal("CleanOldTransactionChore uncaughtException: " + t.getName(), e);
                    }
                };

                String n = Thread.currentThread().getName();

                if (TransactionalLeasesThread == null) {
                    TransactionalLeasesThread = new Thread(this.transactionLeases);
                    if (TransactionalLeasesThread != null) {
                        Threads.setDaemonThreadRunning(TransactionalLeasesThread, "Transactional leases");
                    }
                }
            } catch (Exception e) {
                throw new CoprocessorException("SsccRegionEndpoint coprocessor: start threw exception " + e);
            }
        }

        this.t_Region = (TransactionalRegion) tmp_env.getRegion();
        this.fs = this.m_Region.getFilesystem();
        tHLog = this.m_Region.getLog();

        RegionServerServices rss = tmp_env.getRegionServerServices();
        ServerName sn = rss.getServerName();
        lv_hostName = sn.getHostname();
        lv_port = sn.getPort();
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: Hostname " + lv_hostName + " port " + lv_port);
        this.regionInfo = this.m_Region.getRegionInfo();
        this.nextLogSequenceId = this.m_Region.getSequenceId();
        this.t_Region = (TransactionalRegion) tmp_env.getRegion();
        zkw1 = rss.getZooKeeper();

        this.configuredEarlyLogging = conf.getBoolean("hbase.regionserver.region.transactional.earlylogging",
                false);

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: get the reference from Region CoprocessorEnvrionment ");

        if (tmp_env.getSharedData().isEmpty())
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: shared map is empty ");
            else if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: shared map is NOT empty Yes ... ");

        transactionsByIdTestz = TrxRegionObserver.getRefMap();

        if (transactionsByIdTestz.isEmpty())
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: reference map is empty ");
            else if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: reference map is NOT empty Yes ... ");

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: UUU Region " + this.m_Region.getRegionNameAsString()
                    + " check indoubt list from reference map ");

        indoubtTransactionsById = (TreeMap<Long, WALEdit>) transactionsByIdTestz
                .get(this.m_Region.getRegionNameAsString() + TrxRegionObserver.trxkeypendingTransactionsById);

        indoubtTransactionsCountByTmid = (TreeMap<Integer, Integer>) transactionsByIdTestz.get(
                this.m_Region.getRegionNameAsString() + TrxRegionObserver.trxkeyindoubtTransactionsCountByTmid);
        if (indoubtTransactionsCountByTmid != null) {
            if (LOG.isTraceEnabled())
                LOG.trace(
                        "SsccRegionEndpoint coprocessor:OOO successfully get the reference from Region CoprocessorEnvrionment ");
        }
        try {
            idServer = new IdTm(false);
        } catch (Exception e) {
            LOG.error("SsccRegionEndpoint coprocessor:  unble to new IdTm " + e);
        }
        long logSeqId = nextLogSequenceId.get();
        long currentTime = System.currentTimeMillis();
        long ssccSeqId = currentTime > logSeqId ? currentTime : logSeqId;
        nextSsccSequenceId = new AtomicLong(ssccSeqId);
        LOG.info("Generate SequenceID start from " + nextSsccSequenceId);

        LOG.info("SsccRegionEndpoint coprocessor: start");
    }

    @Override
    public void stop(CoprocessorEnvironment env) throws IOException {
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: stop ");
        stoppable.stop("stop() SsccRegionEndpoint");
    }

    // Internal support methods

    /**
     * Checks if the region is closing
     * @param long transactionId
     * @return String 
     * @throws IOException 
     */
    private void checkClosing(final long transactionId) throws IOException {
        if (closing) {
            LOG.error("SsccRegionEndpoint coprocessor:  Trafodion Recovery: checkClosing(" + transactionId
                    + ") - raising exception. no more transaction allowed.");
            throw new IOException("closing region, no more transaction allowed");
        }
    }

    public void deleteRecoveryzNode(int node, String encodedName) throws IOException {

        synchronized (zkRecoveryCheckLock) {
            // default zNodePath
            String zNodeKey = lv_hostName + "," + lv_port + "," + encodedName;

            StringBuilder sb = new StringBuilder();
            sb.append("TM");
            sb.append(node);
            String str = sb.toString();
            String zNodePathTM = zNodePath + str;
            String zNodePathTMKey = zNodePathTM + "/" + zNodeKey;
            if (LOG.isTraceEnabled())
                LOG.trace("Trafodion Recovery Region Observer CP: ZKW Delete region recovery znode" + node
                        + " zNode Path " + zNodePathTMKey);
            // delete zookeeper recovery zNode, call ZK ...
            try {
                ZKUtil.deleteNodeFailSilent(zkw1, zNodePathTMKey);
            } catch (KeeperException e) {
                throw new IOException(
                        "Trafodion Recovery Region Observer CP: ZKW Unable to delete recovery zNode to TM " + node,
                        e);
            }
        }
    } // end of deleteRecoveryzNode

    /**
     * Starts the region after a recovery
     */
    public void startRegionAfterRecovery() throws IOException {
        boolean isFlush = false;

        try {
            if (LOG.isTraceEnabled())
                LOG.trace(
                        "SsccRegionEndpoint coprocessor:  Trafodion Recovery:  Flushing cache in startRegionAfterRecovery "
                                + m_Region.getRegionInfo().getRegionNameAsString());
            m_Region.flushcache();
            //if (!m_Region.flushcache().isFlushSucceeded()) { 
            //   LOG.trace("SsccRegionEndpoint coprocessor:  Trafodion Recovery:  Flushcache returns false !!! " + m_Region.getRegionInfo().getRegionNameAsString());
            //}
        } catch (IOException e) {
            LOG.error("SsccRegionEndpoint coprocessor:  Trafodion Recovery: Flush failed after replay edits"
                    + m_Region.getRegionInfo().getRegionNameAsString());
            return;
        }

        //FileSystem fileSystem = m_Region.getFilesystem();
        //Path archiveTHLog = new Path (recoveryTrxPath.getParent(),"archivethlogfile.log");
        //if (fileSystem.exists(archiveTHLog)) fileSystem.delete(archiveTHLog, true);
        //if (fileSystem.exists(recoveryTrxPath))fileSystem.rename(recoveryTrxPath,archiveTHLog);
        if (indoubtTransactionsById != null)
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  Trafodion Recovery: region " + recoveryTrxPath + " has "
                        + indoubtTransactionsById.size() + " in-doubt transactions and edits are archived.");
            else if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  Trafodion Recovery: region " + recoveryTrxPath
                        + " has 0 in-doubt transactions and edits are archived.");
        regionState = 2;
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  Trafodion Recovery: region "
                    + m_Region.getRegionInfo().getEncodedName() + " is STARTED.");
    }

    /**
     * Rssolves the transaction from the log
     * @param SsccTransactionState transactionState
     * @throws IOException 
     */
    private void resolveTransactionFromLog(final SsccTransactionState transactionState) throws IOException {
        LOG.error(
                "SsccRegionEndpoint coprocessor:  Global transaction log is not Implemented. (Optimisticly) assuming transaction commit!");
        commit(transactionState);
    }

    /**
     * TransactionLeaseListener
     */
    private class TransactionLeaseListener implements LeaseListener {

        //private final long transactionName;
        private final String transactionName;

        TransactionLeaseListener(final long n) {
            this.transactionName = getTransactionalUniqueId(n);
        }

        public void leaseExpired() {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor:  leaseExpired Transaction [" + this.transactionName
                        + "] expired in region [" + m_Region.getRegionInfo().getRegionNameAsString() + "]");
            SsccTransactionState s = null;
            synchronized (transactionsById) {
                s = transactionsById.remove(transactionName);
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:  leaseExpired Removing transaction: "
                            + this.transactionName + " from list");

                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor:  leaseExpired Removing transaction: "
                            + this.transactionName + " from list");
            }
            if (s == null) {
                LOG.warn("leaseExpired Unknown transaction expired " + this.transactionName);
                return;
            }
            switch (s.getStatus()) {
            case PENDING:
                s.setStatus(Status.ABORTED);
                break;
            case COMMIT_PENDING:
                if (LOG.isTraceEnabled())
                    LOG.trace("SsccRegionEndpoint coprocessor: leaseExpired  Transaction " + s.getTransactionId()
                            + " expired in COMMIT_PENDING state");
                String key = getTransactionalUniqueId(s.getTransactionId());
                try {
                    if (s.getCommitPendingWaits() > MAX_COMMIT_PENDING_WAITS) {
                        if (LOG.isTraceEnabled())
                            LOG.trace(
                                    "SsccRegionEndpoint coprocessor: leaseExpired  Checking transaction status in transaction log");
                        resolveTransactionFromLog(s);
                        break;
                    }
                    if (LOG.isTraceEnabled())
                        LOG.trace(
                                "SsccRegionEndpoint coprocessor: leaseExpired  renewing lease and hoping for commit");
                    s.incrementCommitPendingWaits();
                    synchronized (transactionsById) {
                        transactionsById.put(key, s);
                        if (LOG.isTraceEnabled())
                            LOG.trace("SsccRegionEndpoint coprocessor: leaseExpired  Adding transaction: "
                                    + s.getTransactionId() + " to list");
                    }
                    try {
                        transactionLeases.createLease(key, transactionLeaseTimeout, this);
                    } catch (LeaseStillHeldException e) {
                        transactionLeases.renewLease(key);
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

                break;

            default:
                LOG.warn("SsccRegionEndpoint coprocessor: leaseExpired  Unexpected status on expired lease");
            }
        }
    }

    /**
     * Processes multiple transactional deletes    
     * @param long transactionId
     * @param Delete[] deletes   
     * @throws IOException 
     */
    public synchronized void delete(long transactionId, long startId, Delete[] deletes) throws IOException {
        if (LOG.isTraceEnabled())
            LOG.trace("Enter SsccRegionEndpoint coprocessor: deletes[], txid: " + transactionId);
        checkClosing(transactionId);

        SsccTransactionState state = this.beginTransIfNotExist(transactionId, startId);

        //for (Delete del : deletes) {
        //  state.addDelete(del);
        //}
    }

    public void constructIndoubtTransactions() /*throws IdTmException*/ {

        synchronized (recoveryCheckLock) {
            if ((indoubtTransactionsById == null) || (indoubtTransactionsById.size() == 0)) {
                if (LOG.isTraceEnabled())
                    LOG.trace(
                            "Trafodion Recovery Endpoint Coprocessor: Region " + regionInfo.getRegionNameAsString()
                                    + " has no in-doubt transaction, set region START ");
                regionState = 2; // region is started for transactional access
                reconstructIndoubts = 1;
                try {
                    startRegionAfterRecovery();
                } catch (IOException exp1) {
                    LOG.debug("Trafodion Recovery: flush error during region start");
                }
                return;
            }

            if (LOG.isTraceEnabled())
                LOG.trace(
                        "Trafodion Recovery Endpoint Coprocessor: Trafodion Recovery RegionObserver to Endpoint coprocessor data exchange test");
            if (LOG.isTraceEnabled())
                LOG.trace(
                        "Trafodion Recovery Endpoint Coprocessor: try to access indoubt transaction list with size "
                                + indoubtTransactionsById.size());

            if (reconstructIndoubts == 0) {
                //Retrieve (tid,Edits) from indoubt Transaction and construct/add into desired transaction data list
                for (Entry<Long, WALEdit> entry : indoubtTransactionsById.entrySet()) {
                    long transactionId = entry.getKey();
                    String key = String.valueOf(transactionId);
                    if (LOG.isTraceEnabled())
                        LOG.trace("Trafodion Recovery Endpoint Coprocessor:E11 Region "
                                + regionInfo.getRegionNameAsString() + " process in-doubt transaction "
                                + transactionId);

                    IdTmId seqId;
                    //                      try {
                    //                         seqId = new IdTmId();
                    //                         if (LOG.isDebugEnabled()) LOG.debug("Trafodion Recovery Endpoint Coprocessor:getting new IdTM sequence ");
                    //                         idServer.id(ID_TM_SERVER_TIMEOUT, seqId);
                    //                         if (LOG.isDebugEnabled()) LOG.debug("Trafodion Recovery Endpoint Coprocessor: IdTM sequence is " + seqId.val);
                    //                      } catch (IdTmException exc) {
                    //                         LOG.error("Trafodion Recovery Endpoint Coprocessor: IdTm threw exception exc " + exc);
                    //                         throw new IdTmException("Trafodion Recovery Endpoint Coprocessor: IdTm threw exception exc " + exc);
                    //                      } catch (Exception exc2) {
                    //                         LOG.error("Trafodion Recovery Endpoint Coprocessor: IdTm threw exception exc2 " + exc2);
                    //                         throw new IdTmException("Trafodion Recovery Endpoint Coprocessor: IdTm threw exception exc2 " + exc2);
                    //                      }

                    //TBD Need to get HLOG ???
                    if (LOG.isTraceEnabled())
                        LOG.trace("constructIndoubtTransactions for transId " + transactionId);
                    SsccTransactionState state = new SsccTransactionState(
                            transactionId, /* 1L my_Region.getLog().getSequenceNumber()*/
                            nextLogSequenceId.getAndIncrement(), nextLogSequenceId, regionInfo,
                            m_Region.getTableDesc(), tHLog, false,
                            //                                                                                seqId.val);
                            nextSsccSequenceId.getAndIncrement());
                    if (LOG.isTraceEnabled())
                        LOG.trace("Trafodion Recovery Endpoint Coprocessor:E22 Region "
                                + regionInfo.getRegionNameAsString() + " create transaction state for "
                                + transactionId);

                    state.setStartSequenceNumber(state.getStartId());
                    transactionsById.put(getTransactionalUniqueId(transactionId), state);

                    state.setReinstated();
                    state.setStatus(Status.COMMIT_PENDING);
                    commitPendingTransactions.add(state);
                    //                      try {
                    //                         idServer.id(ID_TM_SERVER_TIMEOUT, seqId);
                    //                      } catch (IdTmException exc) {
                    //                         LOG.error("Trafodion Recovery Endpoint Coprocessor: IdTm threw exception 2 " + exc);
                    //                      }
                    //            state.setSequenceNumber(seqId.val);
                    if (LOG.isTraceEnabled())
                        LOG.trace("Trafodion Recovery Endpoint setting sequenceNumber to commitId: "
                                + state.getCommitId());
                    state.setSequenceNumber(state.getCommitId());
                    //            state.setSequenceNumber(nextSsccSequenceId.getAndIncrement());
                    commitedTransactionsBySequenceNumber.put(state.getSequenceNumber(), state);
                    int tmid = (int) (transactionId >> 32);
                    if (LOG.isTraceEnabled())
                        LOG.trace("Trafodion Recovery Endpoint Coprocessor:E33 Region "
                                + regionInfo.getRegionNameAsString() + " add prepared " + transactionId + " to TM "
                                + tmid);
                } // for all txns in indoubt transcation list
            } // not reconstruct indoubtes yet
            reconstructIndoubts = 1;
        } // synchronized
        /* //TBD cleanup lists (this is for testing purpose only)
        LOG.debug("Trafodion Recovery Endpoint Coprocessor:EEE Clean up recovery test for indoubt transactions");
        transactionsById.clear();
        commitPendingTransactions.clear();
        commitedTransactionsBySequenceNumber.clear();
        LOG.debug("Trafodion Recovery Endpoint Coprocessor:EEE Clean up indoubt transactions in data lists");
        */
    }

    /**
     * Obtains a scanner lease id
     * @param long scannerId
     * @return String 
     */
    private String getScannerLeaseId(final long scannerId) {
        String lstring = m_Region.getRegionInfo().getRegionNameAsString() + scannerId;

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor:  getScannerLeaseId -- EXIT txId: " + scannerId
                    + " lease string " + lstring);
        return m_Region.getRegionInfo().getRegionNameAsString() + scannerId;
    }

    /**
     * Obtains a transactional lease id
     * @param long transactionId
     * @return String 
     */
    private String getTransactionalUniqueId(final long transactionId) {

        if (LOG.isTraceEnabled()) {
            String lstring = m_Region.getRegionInfo().getRegionNameAsString() + transactionId;
            LOG.trace("SsccRegionEndpoint coprocessor:  getTransactionalUniqueId -- EXIT txId: " + transactionId
                    + " transactionsById size: " + transactionsById.size() + " name " + lstring);
        }

        return m_Region.getRegionInfo().getRegionNameAsString() + transactionId;
    }

    /**
     * Formats a cleanup message for a Throwable
     * @param Throwable t
     * @param String msg
     * @return Throwable
     */
    private Throwable cleanup(final Throwable t, final String msg) {
        if (t instanceof NotServingRegionException) {
            if (LOG.isTraceEnabled())
                LOG.trace("NotServingRegionException; " + t.getMessage());
            return t;
        }
        if (msg == null) {
            LOG.error("cleanup message was null");
        } else {
            LOG.error("cleanup message was " + msg);
        }
        return t;
    }

    private IOException convertThrowableToIOE(final Throwable t) {
        return convertThrowableToIOE(t, null);
    }

    /*
     * @param t
     *
     * @param msg Message to put in new IOE if passed <code>t</code>
     * is not an IOE
     *
     * @return Make <code>t</code> an IOE if it isn't already.
     */
    private IOException convertThrowableToIOE(final Throwable t, final String msg) {
        return (t instanceof IOException ? (IOException) t
                : msg == null || msg.length() == 0 ? new IOException(t) : new IOException(msg, t));
    }

    /**
     * Checks if the file system is available       
     * @return boolean
     */
    public boolean checkFileSystem() {
        if (this.fs != null) {
            try {
                FSUtils.checkFileSystemAvailable(this.fs);
            } catch (IOException e) {
                if (LOG.isTraceEnabled())
                    LOG.trace("File System not available threw IOException " + e.getMessage());
                return false;
            }
        }
        return true;
    }

    /**
     * Prepares the family keys if the scan has no families defined
     * @param Scan scan
     * @throws IOException
     */
    public void prepareScanner(Scan scan) throws IOException {
        if (!scan.hasFamilies()) {
            for (byte[] family : this.m_Region.getTableDesc().getFamiliesKeys()) {
                scan.addFamily(family);
            }
        }
    }

    /**
     * Checks if the row is within this region's row range
     * @param byte[] row  
     * @param String op
     * @throws IOException
     */
    public void checkRow(final byte[] row, String op) throws IOException {
        if (!this.m_Region.rowIsInRange(this.regionInfo, row)) {
            throw new WrongRegionException("Requested row out of range for " + op + " on HRegion " + this
                    + ", startKey='" + Bytes.toStringBinary(this.regionInfo.getStartKey()) + "', getEndKey()='"
                    + Bytes.toStringBinary(this.regionInfo.getEndKey()) + "', row='" + Bytes.toStringBinary(row)
                    + "'");
        }
    }

    /**
     * Removes the scanner associated with the specified ID from the internal
     * id->scanner TransactionalRegionScannerHolder map
     *
     * @param long scannerId
     * @return a Scanner or throws UnknownScannerException
     * @throws UnknownScannerException
     */
    protected synchronized RegionScanner removeScanner(long scannerId) throws UnknownScannerException {

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: removeScanner scanners map is " + scanners + ", count is "
                    + scanners.size());
        TransactionalRegionScannerHolder rsh = scanners.remove(scannerId);
        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: removeScanner scanners map is " + scanners + ", count is "
                    + scanners.size());
        if (rsh != null) {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: removeScanner rsh is " + rsh + "rsh.s is" + rsh.s);
            return rsh.s;
        } else {
            if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: removeScanner rsh is null");
            throw new UnknownScannerException("ScannerId: " + scannerId + ", already closed?");
        }
    }

    /**
     * Adds a region scanner to the TransactionalRegionScannerHolder map
     * @param RegionScanner s
     * @param HRegion r       
     * @return long 
     * @throws LeaseStillHeldException 
     */
    protected synchronized long addScanner(long transId, RegionScanner s, HRegion r)
            throws LeaseStillHeldException {
        long scannerId = performScannerId.getAndIncrement();

        TransactionalRegionScannerHolder rsh = new TransactionalRegionScannerHolder(transId, scannerId, s, r);

        if (rsh != null)
            if (LOG.isTraceEnabled())
                LOG.trace(
                        "SsccRegionEndpoint coprocessor: scannerId is " + scannerId + ", addScanner rsh is " + rsh);
            else if (LOG.isTraceEnabled())
                LOG.trace("SsccRegionEndpoint coprocessor: scannerId is " + scannerId + ", addScanner rsh is null");

        TransactionalRegionScannerHolder existing = scanners.putIfAbsent(scannerId, rsh);

        if (LOG.isTraceEnabled())
            LOG.trace("SsccRegionEndpoint coprocessor: addScanner scanners map is " + scanners + ", count is "
                    + scanners.size());

        /*
            scannerLeases.createLease(getScannerLeaseId(scannerId),
                          this.scannerLeaseTimeoutPeriod,
                          new TransactionalScannerListener(scannerId));
        */

        return scannerId;
    }

    /**
     *    * Instantiated as a scanner lease. If the lease times out, the scanner is
     *       * closed
     *          */
    /*
      private class TransactionalScannerListener implements LeaseListener {
        private final long scannerId;
        
        TransactionalScannerListener(final long id) {
          this.scannerId = id;
        }
        
        @Override
        public void leaseExpired() {
          TransactionalRegionScannerHolder rsh = scanners.remove(this.scannerId);
          if (rsh != null) {
    RegionScanner s = rsh.s;
    if (LOG.isTraceEnabled()) LOG.trace("Scanner " + this.scannerId + " lease expired on region "
        + s.getRegionInfo().getRegionNameAsString());
    try {
      HRegion region = rsh.r;
        
      s.close();
    } catch (IOException e) {
      LOG.error("Closing scanner for "
          + s.getRegionInfo().getRegionNameAsString(), e);
    }
          } else {
    if (LOG.isTraceEnabled()) LOG.trace("Scanner " + this.scannerId + " lease expired");
          }
        }
      }
    */

    /**
     * Formats the throwable stacktrace to a string
     * @param Throwable e
     * @return String 
     */
    public String stackTraceToString(Throwable e) {
        StringBuilder sb = new StringBuilder();
        for (StackTraceElement element : e.getStackTrace()) {
            sb.append(element.toString());
            sb.append("\n");
        }
        return sb.toString();
    }

    /**
     * Returns the Scanner Leases for this coprocessor                       
     * @return Leases 
     */
    //synchronized protected Leases getScannerLeases() {
    //  return this.scannerLeases;
    //}

    /**
     * Returns the Leases for this coprocessor                               
     * @return Leases 
     */
    synchronized protected Leases getTransactionalLeases() {
        return this.transactionLeases;
    }

    /**
     * Removes unneeded committed transactions                               
     */
    synchronized public void removeUnNeededCommitedTransactions() {

        Long minStartSeqNumber = getMinStartSequenceNumber();

        if (minStartSeqNumber == null) {
            minStartSeqNumber = Long.MAX_VALUE;
        }

        int numRemoved = 0;

        synchronized (commitedTransactionsBySequenceNumber) {
            for (Entry<Long, SsccTransactionState> entry : new LinkedList<Entry<Long, SsccTransactionState>>(
                    commitedTransactionsBySequenceNumber.entrySet())) {
                if (entry.getKey() >= minStartSeqNumber) {
                    break;
                }
                numRemoved = numRemoved
                        + (commitedTransactionsBySequenceNumber.remove(entry.getKey()) == null ? 0 : 1);
                numRemoved++;
            }
        }

        /*
           StringBuilder traceMessage = new StringBuilder();
           if (numRemoved > 0) {
             traceMessage.append("Removed [").append(numRemoved)
        .append("] commited transactions");
            
                  if (minStartSeqNumber == Integer.MAX_VALUE) {
        traceMessage.append(" with any sequence number.");
             } else {
               traceMessage.append(" with sequence lower than [")
               .append(minStartSeqNumber).append("].");
             }
            
             if (!commitedTransactionsBySequenceNumber.isEmpty()) {
                 traceMessage.append(" Still have [")
                      .append(commitedTransactionsBySequenceNumber.size())
                      .append("] left.");
             } else {
               traceMessage.append(" None left.");
             }
               if (LOG.isTraceEnabled()) LOG.trace(traceMessage.toString());
                } else if (commitedTransactionsBySequenceNumber.size() > 0) {
                  traceMessage.append("Could not remove any transactions, and still have ")
          .append(commitedTransactionsBySequenceNumber.size())
          .append(" left");
                  if (LOG.isTraceEnabled()) LOG.trace(traceMessage.toString());
                }
        */

    }

    /**
     * Returns the minimum start sequence number
     * @return Long
     */
    private Long getMinStartSequenceNumber() {

        List<SsccTransactionState> transactionStates;

        synchronized (transactionsById) {
            transactionStates = new ArrayList<SsccTransactionState>(transactionsById.values());
        }

        Long min = null;

        for (SsccTransactionState transactionState : transactionStates) {
            if (min == null || transactionState.getStartSequenceNumber() < min) {
                min = transactionState.getStartSequenceNumber();
            }
        }

        return min;
    }

    /**
     * Returns the region name as a string
     * @return String 
     */
    public String getRegionNameAsString() {
        return this.m_Region.getRegionNameAsString();
    }

    /**
     * Simple helper class that just keeps track of whether or not its stopped.
     */
    private static class StoppableImplementation implements Stoppable {
        private volatile boolean stop = false;

        @Override
        public void stop(String why) {
            this.stop = true;
        }

        @Override
        public boolean isStopped() {
            return this.stop;
        }
    }
}

//1}