package com.tesora.dve.server.connectionmanager;
/*
* #%L
* Tesora Inc.
* Database Virtualization Engine
* %%
* Copyright (C) 2011 - 2014 Tesora Inc.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.tesora.dve.server.global.HostService;
import com.tesora.dve.singleton.Singletons;
import org.apache.log4j.Logger;
import com.tesora.dve.common.catalog.CatalogDAO;
import com.tesora.dve.common.catalog.TransactionRecord;
import com.tesora.dve.exceptions.PECodingException;
import com.tesora.dve.exceptions.PEException;
public class Transaction2PCTracker {
private static Logger logger = Logger.getLogger(Transaction2PCTracker.class);
enum TxnState { INIT, PREPARE, COMMIT, CLOSED };
final TransactionRecord txnRec;
TxnState txnState;
Future<Boolean> pendingOp;
public Transaction2PCTracker(String transId) {
this.txnRec = new TransactionRecord(transId);
this.txnState = TxnState.INIT;
}
public void startPrepare() {
if (txnState != TxnState.INIT)
throw new PECodingException("Attempt to re-execute transaction prepare");
pendingOp = Singletons.require(HostService.class).submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return txnRec.recordPrepare(CatalogDAO.getCatalogDS());
}
});
txnState = TxnState.PREPARE;
}
public void startCommit() throws PEException {
if (txnState != TxnState.PREPARE)
throw new PECodingException("Attempt to execute 2PC commit without prepare");
finishPrepare();
if (!txnRec.recordCommit(CatalogDAO.getCatalogDS()))
throw new PECodingException("Unable to execute 2PC commit");
txnState = TxnState.COMMIT;
}
public void clearTransactionRecord() throws PEException {
if (txnState == TxnState.PREPARE)
finishPrepare();
Singletons.require(HostService.class).execute(new Runnable() {
@Override
public void run() {
try {
txnRec.clearTransactionRecord(CatalogDAO.getCatalogDS());
} catch (Throwable t) {
logger.warn("Exception cleaning up transaction record for transaction " + txnRec.getXid(), t);
}
}
});
txnState = TxnState.CLOSED;
}
public static void clearOldTransactionRecords() throws PEException {
Singletons.require(HostService.class).execute(new Runnable() {
@Override
public void run() {
try {
TransactionRecord.clearOldTransactionRecords(CatalogDAO.getCatalogDS());
} catch (Throwable t) {
logger.warn("Exception cleaning up old transaction records", t);
}
}
});
}
private void finishPrepare() throws PEException {
try {
if (false == pendingOp.get())
throw new PECodingException("Could not record prepare");
} catch (InterruptedException e) {
throw new PEException("Transaction Prepare Transcription was interrupted", e);
} catch (ExecutionException e) {
throw new PEException("Failure trying to record prepare of transaction", e);
}
}
public static Map<String, Boolean> getGlobalCommitMap() throws PEException {
return TransactionRecord.getGlobalCommitMap(CatalogDAO.getCatalogDS());
}
public static Map<String, Boolean> getCommitMapForHost(String host) throws PEException {
return TransactionRecord.getCommitMapByHost(CatalogDAO.getCatalogDS(), host);
}
}