Package co.cask.tephra

Source Code of co.cask.tephra.TransactionSystemTest

/*
* Copyright © 2012-2014 Cask Data, Inc.
*
* 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.
*/

package co.cask.tephra;

import co.cask.tephra.persist.TransactionSnapshot;
import co.cask.tephra.persist.TransactionStateStorage;

import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Assert;
import org.junit.Test;

import java.util.Arrays;
import java.util.Collection;

/**
*
*/
public abstract class TransactionSystemTest {

  public static final byte[] C1 = Bytes.toBytes("change1");
  public static final byte[] C2 = Bytes.toBytes("change2");
  public static final byte[] C3 = Bytes.toBytes("change3");
  public static final byte[] C4 = Bytes.toBytes("change4");

  protected abstract TransactionSystemClient getClient() throws Exception;

  protected abstract TransactionStateStorage getStateStorage() throws Exception;

  @Test
  public void testCommitRaceHandling() throws Exception {
    TransactionSystemClient client1 = getClient();
    TransactionSystemClient client2 = getClient();

    Transaction tx1 = client1.startShort();
    Transaction tx2 = client2.startShort();

    Assert.assertTrue(client1.canCommit(tx1, asList(C1, C2)));
    // second one also can commit even thought there are conflicts with first since first one hasn't committed yet
    Assert.assertTrue(client2.canCommit(tx2, asList(C2, C3)));

    Assert.assertTrue(client1.commit(tx1));

    // now second one should not commit, since there are conflicts with tx1 that has been committed
    Assert.assertFalse(client2.commit(tx2));
  }

  @Test
  public void testMultipleCommitsAtSameTime() throws Exception {
    // We want to check that if two txs finish at same time (wrt tx manager) they do not overwrite changesets of each
    // other in tx manager used for conflicts detection (we had this bug)
    // NOTE: you don't have to use multiple clients for that
    TransactionSystemClient client1 = getClient();
    TransactionSystemClient client2 = getClient();
    TransactionSystemClient client3 = getClient();
    TransactionSystemClient client4 = getClient();
    TransactionSystemClient client5 = getClient();

    Transaction tx1 = client1.startShort();
    Transaction tx2 = client2.startShort();
    Transaction tx3 = client3.startShort();
    Transaction tx4 = client4.startShort();
    Transaction tx5 = client5.startShort();

    Assert.assertTrue(client1.canCommit(tx1, asList(C1)));
    Assert.assertTrue(client1.commit(tx1));

    Assert.assertTrue(client2.canCommit(tx2, asList(C2)));
    Assert.assertTrue(client2.commit(tx2));

    // verifying conflicts detection
    Assert.assertFalse(client3.canCommit(tx3, asList(C1)));
    Assert.assertFalse(client4.canCommit(tx4, asList(C2)));
    Assert.assertTrue(client5.canCommit(tx5, asList(C3)));
  }

  @Test
  public void testCommitTwice() throws Exception {
    TransactionSystemClient client = getClient();
    Transaction tx = client.startShort();

    Assert.assertTrue(client.canCommit(tx, asList(C1, C2)));
    Assert.assertTrue(client.commit(tx));
    // cannot commit twice same tx
    try {
      Assert.assertFalse(client.commit(tx));
      Assert.fail();
    } catch (TransactionNotInProgressException e) {
      // expected
    }
  }

  @Test
  public void testAbortTwice() throws Exception {
    TransactionSystemClient client = getClient();
    Transaction tx = client.startShort();

    Assert.assertTrue(client.canCommit(tx, asList(C1, C2)));
    client.abort(tx);
    // abort of not active tx has no affect
    client.abort(tx);
  }

  @Test
  public void testReuseTx() throws Exception {
    TransactionSystemClient client = getClient();
    Transaction tx = client.startShort();

    Assert.assertTrue(client.canCommit(tx, asList(C1, C2)));
    Assert.assertTrue(client.commit(tx));
    // can't re-use same tx again
    try {
      client.canCommit(tx, asList(C3, C4));
      Assert.fail();
    } catch (TransactionNotInProgressException e) {
      // expected
    }
    try {
      Assert.assertFalse(client.commit(tx));
      Assert.fail();
    } catch (TransactionNotInProgressException e) {
      // expected
    }

    // abort of not active tx has no affect
    client.abort(tx);
  }

  @Test
  public void testUseNotStarted() throws Exception {
    TransactionSystemClient client = getClient();
    Transaction tx1 = client.startShort();
    Assert.assertTrue(client.commit(tx1));

    // we know this is one is older than current writePointer and was not used
    Transaction txOld = new Transaction(tx1.getReadPointer(), tx1.getWritePointer() - 1,
                                        new long[] {}, new long[] {}, Transaction.NO_TX_IN_PROGRESS);
    try {
      Assert.assertFalse(client.canCommit(txOld, asList(C3, C4)));
      Assert.fail();
    } catch (TransactionNotInProgressException e) {
      // expected
    }
    try {
      Assert.assertFalse(client.commit(txOld));
      Assert.fail();
    } catch (TransactionNotInProgressException e) {
      // expected
    }
    // abort of not active tx has no affect
    client.abort(txOld);

    // we know this is one is newer than current readPointer and was not used
    Transaction txNew = new Transaction(tx1.getReadPointer(), tx1.getWritePointer() + 1,
                                        new long[] {}, new long[] {}, Transaction.NO_TX_IN_PROGRESS);
    try {
      Assert.assertFalse(client.canCommit(txNew, asList(C3, C4)));
      Assert.fail();
    } catch (TransactionNotInProgressException e) {
      // expected
    }
    try {
      Assert.assertFalse(client.commit(txNew));
      Assert.fail();
    } catch (TransactionNotInProgressException e) {
      // expected
    }
    // abort of not active tx has no affect
    client.abort(txNew);
  }

  @Test
  public void testAbortAfterCommit() throws Exception {
    TransactionSystemClient client = getClient();
    Transaction tx = client.startShort();

    Assert.assertTrue(client.canCommit(tx, asList(C1, C2)));
    Assert.assertTrue(client.commit(tx));
    // abort of not active tx has no affect
    client.abort(tx);
  }

  // todo add test invalidate method
  @Test
  public void testInvalidateTx() throws Exception {
    TransactionSystemClient client = getClient();
    // Invalidate an in-progress tx
    Transaction tx1 = client.startShort();
    client.canCommit(tx1, asList(C1, C2));
    Assert.assertTrue(client.invalidate(tx1.getWritePointer()));
    // Cannot invalidate a committed tx
    Transaction tx2 = client.startShort();
    client.canCommit(tx2, asList(C3, C4));
    client.commit(tx2);
    Assert.assertFalse(client.invalidate(tx2.getWritePointer()));
  }

  @Test
  public void testResetState() throws Exception {
    // have tx in progress, committing and committed then reset,
    // get the last snapshot and see that it is empty
    TransactionSystemClient client = getClient();
    TransactionStateStorage stateStorage = getStateStorage();

    Transaction tx1 = client.startShort();
    Transaction tx2 = client.startShort();
    client.canCommit(tx1, asList(C1, C2));
    client.commit(tx1);
    client.canCommit(tx2, asList(C3, C4));

    Transaction txPreReset = client.startShort();
    long currentTs = System.currentTimeMillis();
    client.resetState();

    TransactionSnapshot snapshot = stateStorage.getLatestSnapshot();
    Assert.assertTrue(snapshot.getTimestamp() >= currentTs);
    Assert.assertEquals(0, snapshot.getInvalid().size());
    Assert.assertEquals(0, snapshot.getInProgress().size());
    Assert.assertEquals(0, snapshot.getCommittingChangeSets().size());
    Assert.assertEquals(0, snapshot.getCommittedChangeSets().size());

    // confirm that transaction IDs are not reset
    Transaction txPostReset = client.startShort();
    Assert.assertTrue("New tx ID should be greater than last ID before reset",
                      txPostReset.getWritePointer() > txPreReset.getWritePointer());
  }

  private Collection<byte[]> asList(byte[]... val) {
    return Arrays.asList(val);
  }
}
TOP

Related Classes of co.cask.tephra.TransactionSystemTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.