use of org.apache.tephra.TransactionContext in project cdap by caskdata.
the class PartitionedFileSetTest method testRollbackOfPartitionCreateThenDelete.
@Test
public void testRollbackOfPartitionCreateThenDelete() throws Exception {
PartitionedFileSet pfs = dsFrameworkUtil.getInstance(pfsInstance);
TransactionContext txContext = new TransactionContext(txClient, (TransactionAware) pfs);
// because the previous transaction aborted, the partition as well as the file will not exist
txContext.start();
Assert.assertNull(pfs.getPartition(PARTITION_KEY));
PartitionOutput partitionOutput = pfs.getPartitionOutput(PARTITION_KEY);
Location outputLocation = partitionOutput.getLocation().append("file");
Assert.assertFalse(outputLocation.exists());
try (OutputStream outputStream = outputLocation.getOutputStream()) {
// create and write 1 to the file
outputStream.write(1);
}
Assert.assertTrue(outputLocation.exists());
partitionOutput.addPartition();
Assert.assertNotNull(pfs.getPartition(PARTITION_KEY));
pfs.dropPartition(PARTITION_KEY);
txContext.abort();
// the file shouldn't exist because the transaction was aborted (AND because it was dropped at the end of the tx)
Assert.assertFalse(outputLocation.exists());
}
use of org.apache.tephra.TransactionContext in project cdap by caskdata.
the class PartitionedFileSetTest method testRollbackOfPartitionDelete.
@Test
public void testRollbackOfPartitionDelete() throws Exception {
PartitionedFileSet pfs = dsFrameworkUtil.getInstance(pfsInstance);
TransactionContext txContext = new TransactionContext(txClient, (TransactionAware) pfs);
txContext.start();
PartitionOutput output = pfs.getPartitionOutput(PARTITION_KEY);
Location outputLocation = output.getLocation().append("file");
Assert.assertFalse(outputLocation.exists());
try (OutputStream outputStream = outputLocation.getOutputStream()) {
// write 1 to the first file
outputStream.write(1);
}
Assert.assertTrue(outputLocation.exists());
output.addPartition();
Assert.assertNotNull(pfs.getPartition(PARTITION_KEY));
Assert.assertTrue(pfs.getPartition(PARTITION_KEY).getLocation().exists());
txContext.finish();
// because the previous transaction aborted, the partition as well as the file will not exist
txContext.start();
pfs.dropPartition(PARTITION_KEY);
Assert.assertNull(pfs.getPartition(PARTITION_KEY));
Assert.assertFalse(outputLocation.exists());
// create a new partition with the same partition key (same relative path for the partition
PartitionOutput partitionOutput2 = pfs.getPartitionOutput(PARTITION_KEY);
Location outputLocation2 = partitionOutput2.getLocation().append("file");
Assert.assertFalse(outputLocation2.exists());
// create the file
try (OutputStream outputStream = outputLocation2.getOutputStream()) {
// write 2 to the second file
outputStream.write(2);
}
Assert.assertTrue(outputLocation2.exists());
partitionOutput2.addPartition();
txContext.abort();
// since the previous transaction aborted, the partition and its files should still exist
txContext.start();
Assert.assertNotNull(pfs.getPartition(PARTITION_KEY));
Assert.assertTrue(outputLocation.exists());
try (InputStream inputStream = outputLocation.getInputStream()) {
// should be 1, written by the first partition, not 2 (which was written by the second partition)
Assert.assertEquals(1, inputStream.read());
// should be nothing else in the file
Assert.assertEquals(0, inputStream.available());
}
txContext.finish();
}
use of org.apache.tephra.TransactionContext in project cdap by caskdata.
the class PartitionedFileSetTest method testPartitionConsumer.
@Test
public void testPartitionConsumer() throws Exception {
// exercises the edge case of partition consumption, when partitions are being consumed, while another in-progress
// transaction has added a partition, but it has not yet committed, so the partition is not available for the
// consumer
// note: each concurrent transaction needs its own instance of the dataset because the dataset holds the txId
// as an instance variable
PartitionedFileSet dataset1 = dsFrameworkUtil.getInstance(pfsInstance);
PartitionedFileSet dataset2 = dsFrameworkUtil.getInstance(pfsInstance);
PartitionedFileSet dataset3 = dsFrameworkUtil.getInstance(pfsInstance);
// producer simply adds initial partition
TransactionContext txContext1 = new TransactionContext(txClient, (TransactionAware) dataset1);
txContext1.start();
PartitionKey partitionKey1 = generateUniqueKey();
dataset1.getPartitionOutput(partitionKey1).addPartition();
txContext1.finish();
// consumer simply consumes initial partition
TransactionContext txContext2 = new TransactionContext(txClient, (TransactionAware) dataset2);
txContext2.start();
SimplePartitionConsumer partitionConsumer = new SimplePartitionConsumer(dataset2);
List<PartitionDetail> partitions = partitionConsumer.consumePartitions();
Assert.assertEquals(1, partitions.size());
Assert.assertEquals(partitionKey1, partitions.get(0).getPartitionKey());
txContext2.finish();
// producer adds a 2nd partition but does not yet commit the transaction
txContext1.start();
PartitionKey partitionKey2 = generateUniqueKey();
dataset1.getPartitionOutput(partitionKey2).addPartition();
// another producer adds a 3rd partition, but does not yet commit the transaction
TransactionContext txContext3 = new TransactionContext(txClient, (TransactionAware) dataset3);
txContext3.start();
PartitionKey partitionKey3 = generateUniqueKey();
dataset3.getPartitionOutput(partitionKey3).addPartition();
// simply start and commit a transaction so the next transaction's read pointer is higher than the previous
// transaction's write pointer. Otherwise, the previous transaction may not get included in the in-progress list
txContext2.start();
txContext2.finish();
// consumer attempts to consume at a time after the partition was added, but before it committed. Because of this,
// the partition is not visible and will not be consumed
txContext2.start();
Assert.assertTrue(partitionConsumer.consumePartitions().isEmpty());
txContext2.finish();
// both producers commit the transaction in which the second partition was added
txContext1.finish();
txContext3.finish();
// the next time the consumer runs, it processes the second partition
txContext2.start();
partitions = partitionConsumer.consumePartitions();
Assert.assertEquals(2, partitions.size());
// ordering may be different
Assert.assertEquals(ImmutableSet.of(partitionKey2, partitionKey3), ImmutableSet.of(partitions.get(0).getPartitionKey(), partitions.get(1).getPartitionKey()));
txContext2.finish();
}
use of org.apache.tephra.TransactionContext in project cdap by caskdata.
the class PartitionedFileSetTest method testMetadataForNonexistentPartition.
@Test
public void testMetadataForNonexistentPartition() throws Exception {
PartitionedFileSet pfs = dsFrameworkUtil.getInstance(pfsInstance);
PartitionKey key = generateUniqueKey();
TransactionContext txContext = new TransactionContext(txClient, (TransactionAware) pfs);
txContext.start();
try {
// didn't add any partitions to the dataset, so any partition key should throw a PartitionNotFoundException
pfs.addMetadata(key, "metaKey", "metaValue");
Assert.fail("Expected not to find key: " + key);
} catch (PartitionNotFoundException e) {
Assert.assertEquals(pfsInstance.getEntityName(), e.getPartitionedFileSetName());
Assert.assertEquals(key, e.getPartitionKey());
} finally {
txContext.abort();
}
}
use of org.apache.tephra.TransactionContext in project cdap by caskdata.
the class StreamConsumerTestBase method testNamespacedStreamConsumers.
@Test
public void testNamespacedStreamConsumers() throws Exception {
// Test two consumers for two streams with the same name, but in different namespaces. Their consumption should be
// independent of the other.
String stream = "testNamespacedStreamConsumers";
StreamId streamId = TEST_NAMESPACE.stream(stream);
StreamId otherStreamId = OTHER_NAMESPACE.stream(stream);
StreamAdmin streamAdmin = getStreamAdmin();
streamAdmin.create(streamId);
streamAdmin.create(otherStreamId);
StreamConfig streamConfig = streamAdmin.getConfig(streamId);
StreamConfig otherStreamConfig = streamAdmin.getConfig(otherStreamId);
// Writes 5 events to both streams
writeEvents(streamConfig, "Testing ", 5);
writeEvents(otherStreamConfig, "Testing ", 5);
streamAdmin.configureInstances(streamId, 0L, 1);
streamAdmin.configureInstances(otherStreamId, 0L, 1);
StreamConsumerFactory consumerFactory = getConsumerFactory();
StreamConsumer consumer = consumerFactory.create(streamId, "fifo.rollback", new ConsumerConfig(0L, 0, 1, DequeueStrategy.FIFO, null));
StreamConsumer otherConsumer = consumerFactory.create(otherStreamId, "fifo.rollback", new ConsumerConfig(0L, 0, 1, DequeueStrategy.FIFO, null));
// Try to dequeue using both consumers
TransactionContext context = createTxContext(consumer);
TransactionContext otherContext = createTxContext(otherConsumer);
context.start();
otherContext.start();
// Consume events from the stream in the default namespace
DequeueResult<StreamEvent> result0 = consumer.poll(1, 1, TimeUnit.SECONDS);
Assert.assertEquals("Testing 0", Charsets.UTF_8.decode(result0.iterator().next().getBody()).toString());
context.finish();
context.start();
result0 = consumer.poll(1, 1, TimeUnit.SECONDS);
Assert.assertEquals("Testing 1", Charsets.UTF_8.decode(result0.iterator().next().getBody()).toString());
context.finish();
context.start();
result0 = consumer.poll(1, 1, TimeUnit.SECONDS);
Assert.assertEquals("Testing 2", Charsets.UTF_8.decode(result0.iterator().next().getBody()).toString());
context.finish();
context.start();
// Even though a stream with the same name has already consumed 3 events, the otherConsumer is for a stream in a
// different namespace, so it will still be on the initial event.
DequeueResult<StreamEvent> result1 = otherConsumer.poll(1, 1, TimeUnit.SECONDS);
Assert.assertEquals("Testing 0", Charsets.UTF_8.decode(result1.iterator().next().getBody()).toString());
otherContext.finish();
otherContext.start();
result0 = consumer.poll(1, 1, TimeUnit.SECONDS);
result1 = otherConsumer.poll(1, 1, TimeUnit.SECONDS);
Assert.assertEquals("Testing 3", Charsets.UTF_8.decode(result0.iterator().next().getBody()).toString());
Assert.assertEquals("Testing 1", Charsets.UTF_8.decode(result1.iterator().next().getBody()).toString());
// Commit both
context.finish();
otherContext.finish();
consumer.close();
otherConsumer.close();
}
Aggregations