/*
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Dec 26, 2008
*/
package com.bigdata.service;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import com.bigdata.btree.IIndex;
import com.bigdata.btree.IndexMetadata;
import com.bigdata.btree.proc.IIndexProcedure;
import com.bigdata.journal.ITx;
/**
* Unit tests of local (all writes are on a single data service) and distributed
* abort and commit protocols for an {@link IBigdataFederation} using the
* {@link DistributedTransactionService}.
*
* @todo the easiest way to set this up is to place different indices onto
* different data services, using just 2 data services to make setup
* easier.
* <p>
* An alternative setup would pre-partition a single scale-out index so
* that it was on both data services.
*
* @todo There should be explicit tests of distributed transactions that involve
* different indices, including the case where the MDS is participating in
* the tx. This should really be no different, but the tests should cover
* the case anyway. In point, perhaps the easiest thing to do is to register
* different indices on each data service since the commit protocol is
* entirely in terms of the local index resources (it pays no attention
* to scale-out indices, so this is best really).
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public class TestDistributedTransactionService extends
AbstractEmbeddedFederationTestCase {
/**
*
*/
public TestDistributedTransactionService() {
}
/**
* @param arg0
*/
public TestDistributedTransactionService(String arg0) {
super(arg0);
}
// /**
// * Writes a key/val pair on a named index on the specified
// * {@link IDataService}.
// *
// * @param tx
// * The timestamp or transaction identifer.
// * @param ds
// * The {@link IDataService}.
// * @param name
// * The index name.
// *
// * @throws InterruptedException
// * @throws ExecutionException
// * @throws IOException
// */
// protected void doWrite(long tx, IDataService ds, String name)
// throws InterruptedException, ExecutionException, IOException {
//
// ds.submit(tx, name, new IIndexProcedure() {
//
// public Object apply(IIndex ndx) {
//
// // write on the index.
// ndx.insert(new byte[]{1}, new byte[]{1});
//
// return null;
// }
//
// /** read-write. */
// public boolean isReadOnly() {
// return false;
// }});
//
// }
/**
* Unit test of abort of a read-write tx that writes on a single data
* service.
*
* @throws ExecutionException
* @throws InterruptedException
* @throws IOException
*/
public void test_localTxAbort() throws IOException, InterruptedException, ExecutionException {
final String name1 = "ndx1";
{
final IndexMetadata md = new IndexMetadata(name1, UUID
.randomUUID());
md.setIsolatable(true);
dataService1.registerIndex(name1, md);
}
final long tx = fed.getTransactionService().newTx(ITx.UNISOLATED);
// submit write operation to the ds.
dataService1.submit(tx, name1, new IIndexProcedure<Void>(){
private static final long serialVersionUID = 1L;
@Override
public Void apply(final IIndex ndx) {
// write on the index.
ndx.insert(new byte[]{1}, new byte[]{1});
return null;
}
public boolean isReadOnly() {
return false;// read-write.
}}).get();
// verify write not visible to unisolated operation.
dataService1.submit(ITx.UNISOLATED, name1, new IIndexProcedure<Void>(){
private static final long serialVersionUID = 1L;
@Override
public Void apply(final IIndex ndx) {
// verify not in the index.
assertFalse(ndx.contains(new byte[]{1}));
return null;
}
public boolean isReadOnly() {
return false;// read-write.
}}).get();
// abort the tx.
fed.getTransactionService().abort(tx);
// verify write still not visible.
dataService1.submit(ITx.UNISOLATED, name1, new IIndexProcedure<Void>(){
private static final long serialVersionUID = 1L;
@Override
public Void apply(final IIndex ndx) {
// verify not in the index.
assertFalse(ndx.contains(new byte[]{1}));
return null;
}
public boolean isReadOnly() {
return false;// read-write.
}}).get();
// verify operation rejected for aborted read-write tx.
try {
dataService1.submit(tx, name1, new IIndexProcedure<Void>() {
private static final long serialVersionUID = 1L;
@Override
public Void apply(final IIndex ndx) {
// NOP
return null;
}
public boolean isReadOnly() {
return false;// read-write.
}
}).get();
fail("Expecting exception");
} catch (Throwable t) {
log.info("Ignoring expected error: " + t);
}
}
// FIXME full distributed read-write tx support is not finished yet so these
// tests have been commented out.
// /**
// * unit test of commit of a read-write tx that writes on a single data
// * service.
// *
// * @throws IOException
// * @throws ExecutionException
// * @throws InterruptedException
// */
// public void test_localTxCommit() throws InterruptedException,
// ExecutionException, IOException {
//
// final String name1 = "ndx1";
//
// {
// final IndexMetadata md = new IndexMetadata(name1, UUID
// .randomUUID());
//
// md.setIsolatable(true);
//
// dataService1.registerIndex(name1, md);
// }
//
// final long tx = fed.getTransactionService().newTx(ITx.UNISOLATED);
//
// // submit write operation to the ds.
// dataService1.submit(tx, name1, new IIndexProcedure(){
//
// public Object apply(IIndex ndx) {
//
// // write on the index.
// ndx.insert(new byte[]{1}, new byte[]{1});
//
// return null;
// }
//
// public boolean isReadOnly() {
// return false;// read-write.
// }}).get();
//
// // verify write not visible to unisolated operation.
// dataService1.submit(ITx.UNISOLATED, name1, new IIndexProcedure(){
//
// public Object apply(IIndex ndx) {
//
// // verify not in the index.
// assertFalse(ndx.contains(new byte[]{1}));
//
// return null;
// }
//
// public boolean isReadOnly() {
// return false;// read-write.
// }}).get();
//
// // commit the tx.
// final long commitTime = fed.getTransactionService().commit(tx);
//
// // verify write now visible as of that commit time.
// dataService1.submit(commitTime, name1, new IIndexProcedure(){
//
// public Object apply(IIndex ndx) {
//
// // verify in the index.
// assertTrue(ndx.contains(new byte[]{1}));
//
// return null;
// }
//
// public boolean isReadOnly() {
// return true;// read-only.
// }}).get();
//
// // verify operation rejected for committed read-write tx.
// try {
// dataService1.submit(tx, name1, new IIndexProcedure(){
//
// public Object apply(IIndex ndx) {
// // NOP
// return null;
// }
//
// public boolean isReadOnly() {
// return false;// read-write.
// }}).get();
// fail("Expecting exception");
// } catch(Throwable t) {
// log.info("Ignoring expected error: "+t);
// }
//
// }
//
// /**
// * @todo unit test of abort of a read-write tx that writes on a more than
// * one data service.
// */
// public void test_distTxAbort() {
//
// fail("write test");
//
// }
//
// /**
// * @todo unit test of commit of a read-write tx that writes on a more than
// * one data service.
// */
// public void test_distTxCommit() {
//
// fail("write test");
//
// }
}