use of org.apache.tephra.TransactionAware in project cdap by caskdata.
the class DatasetBasedStreamSizeScheduleStoreTest method testDeletion.
private void testDeletion(final ProgramId programId) throws Exception {
final boolean defaultVersion = programId.getVersion().equals(ApplicationId.DEFAULT_VERSION);
DatasetId storeTable = NamespaceId.SYSTEM.dataset(ScheduleStoreTableUtil.SCHEDULE_STORE_DATASET_NAME);
final Table table = datasetFramework.getDataset(storeTable, ImmutableMap.<String, String>of(), null);
Assert.assertNotNull(table);
TransactionExecutor txnl = txExecutorFactory.createExecutor(ImmutableList.of((TransactionAware) table));
final byte[] startKey = Bytes.toBytes(DatasetBasedStreamSizeScheduleStore.KEY_PREFIX);
final byte[] stopKey = Bytes.stopKeyForPrefix(startKey);
txnl.execute(new TransactionExecutor.Subroutine() {
@Override
public void apply() throws Exception {
Scanner scanner = table.scan(startKey, stopKey);
Assert.assertNull(scanner.next());
scanner.close();
}
});
// Create one stream schedule - this will be persisted with new format
scheduleStore.persist(programId, PROGRAM_TYPE, STREAM_SCHEDULE_1, MAP_1, 0L, 0L, 0L, 0L, true);
// Create one stream schedule - based on the old format
txnl.execute(new TransactionExecutor.Subroutine() {
@Override
public void apply() throws Exception {
// Create a programId without version so that we can create a old format schedule
ProgramId defaultProgramId = new ProgramId(programId.getNamespace(), programId.getApplication(), programId.getType(), programId.getProgram());
String newRowKey = scheduleStore.getRowKey(defaultProgramId, PROGRAM_TYPE, STREAM_SCHEDULE_1.getName());
Row row = table.get(Bytes.toBytes(scheduleStore.getRowKey(programId, PROGRAM_TYPE, STREAM_SCHEDULE_1.getName())));
Assert.assertFalse(row.isEmpty());
byte[] oldRowKey = Bytes.toBytes(scheduleStore.removeAppVersion(newRowKey));
for (Map.Entry<byte[], byte[]> entry : row.getColumns().entrySet()) {
table.put(oldRowKey, entry.getKey(), entry.getValue());
}
}
});
// Make sure there are only two stream size schedules
txnl.execute(new TransactionExecutor.Subroutine() {
@Override
public void apply() throws Exception {
Scanner scanner = table.scan(startKey, stopKey);
int numRows = 0;
while (true) {
Row row = scanner.next();
if (row == null) {
break;
}
numRows++;
}
scanner.close();
Assert.assertEquals(2, numRows);
}
});
// This delete should have deleted both the old and new row format
scheduleStore.delete(programId, PROGRAM_TYPE, STREAM_SCHEDULE_1.getName());
txnl.execute(new TransactionExecutor.Subroutine() {
@Override
public void apply() throws Exception {
Scanner scanner = table.scan(startKey, stopKey);
if (defaultVersion) {
Assert.assertNull(scanner.next());
} else {
Assert.assertNotNull(scanner.next());
Assert.assertNull(scanner.next());
}
scanner.close();
}
});
// If the version is not default, we need to delete the row which didn't have a version
if (!defaultVersion) {
txnl.execute(new TransactionExecutor.Subroutine() {
@Override
public void apply() throws Exception {
// Create a programId without version so that we can create row key to delete the old format schedule
ProgramId defaultProgramId = new ProgramId(programId.getNamespace(), programId.getApplication(), programId.getType(), programId.getProgram());
String newRowKey = scheduleStore.getRowKey(defaultProgramId, PROGRAM_TYPE, STREAM_SCHEDULE_1.getName());
byte[] oldRowKey = Bytes.toBytes(scheduleStore.removeAppVersion(newRowKey));
Row row = table.get(oldRowKey);
Assert.assertFalse(row.isEmpty());
table.delete(oldRowKey);
}
});
}
}
use of org.apache.tephra.TransactionAware in project cdap by caskdata.
the class DynamicPartitionerWithAvroTest method runDynamicPartitionerMapReduce.
private void runDynamicPartitionerMapReduce(final List<? extends GenericRecord> records, boolean allowConcurrentWriters, boolean expectedStatus) throws Exception {
ApplicationWithPrograms app = deployApp(AppWithMapReduceUsingAvroDynamicPartitioner.class);
final long now = System.currentTimeMillis();
final Multimap<PartitionKey, GenericRecord> keyToRecordsMap = groupByPartitionKey(records, now);
// write values to the input kvTable
final KeyValueTable kvTable = datasetCache.getDataset(INPUT_DATASET);
Transactions.createTransactionExecutor(txExecutorFactory, kvTable).execute(new TransactionExecutor.Subroutine() {
@Override
public void apply() {
// the keys are not used; it matters that they're unique though
for (int i = 0; i < records.size(); i++) {
kvTable.write(Integer.toString(i), records.get(i).toString());
}
}
});
String allowConcurrencyKey = "dataset." + OUTPUT_DATASET + "." + PartitionedFileSetArguments.DYNAMIC_PARTITIONER_ALLOW_CONCURRENCY;
// run the partition writer m/r with this output partition time
ImmutableMap<String, String> arguments = ImmutableMap.of(OUTPUT_PARTITION_KEY, Long.toString(now), allowConcurrencyKey, Boolean.toString(allowConcurrentWriters));
long startTime = System.currentTimeMillis();
boolean status = runProgram(app, AppWithMapReduceUsingAvroDynamicPartitioner.DynamicPartitioningMapReduce.class, new BasicArguments(arguments));
Assert.assertEquals(expectedStatus, status);
if (!expectedStatus) {
// if we expect the program to fail, no need to check the output data for expected results
return;
}
// Verify notifications
List<Notification> notifications = getDataNotifications(startTime);
Assert.assertEquals(1, notifications.size());
Assert.assertEquals(NamespaceId.DEFAULT.dataset(OUTPUT_DATASET), DatasetId.fromString(notifications.get(0).getProperties().get("datasetId")));
// this should have created a partition in the pfs
final PartitionedFileSet pfs = datasetCache.getDataset(OUTPUT_DATASET);
final Location pfsBaseLocation = pfs.getEmbeddedFileSet().getBaseLocation();
Transactions.createTransactionExecutor(txExecutorFactory, (TransactionAware) pfs).execute(new TransactionExecutor.Subroutine() {
@Override
public void apply() throws IOException {
Map<PartitionKey, PartitionDetail> partitions = new HashMap<>();
for (PartitionDetail partition : pfs.getPartitions(null)) {
partitions.put(partition.getPartitionKey(), partition);
// check that the mapreduce wrote the output partition metadata to all the output partitions
Assert.assertEquals(AppWithMapReduceUsingAvroDynamicPartitioner.DynamicPartitioningMapReduce.METADATA, partition.getMetadata().asMap());
}
Assert.assertEquals(3, partitions.size());
Assert.assertEquals(keyToRecordsMap.keySet(), partitions.keySet());
// Check relative paths of the partitions. Also check that their location = pfs baseLocation + relativePath
for (Map.Entry<PartitionKey, PartitionDetail> partitionKeyEntry : partitions.entrySet()) {
PartitionDetail partitionDetail = partitionKeyEntry.getValue();
String relativePath = partitionDetail.getRelativePath();
int zip = (int) partitionKeyEntry.getKey().getField("zip");
Assert.assertEquals(Long.toString(now) + Path.SEPARATOR + zip, relativePath);
Assert.assertEquals(pfsBaseLocation.append(relativePath), partitionDetail.getLocation());
}
for (Map.Entry<PartitionKey, Collection<GenericRecord>> keyToRecordsEntry : keyToRecordsMap.asMap().entrySet()) {
Set<GenericRecord> genericRecords = new HashSet<>(keyToRecordsEntry.getValue());
Assert.assertEquals(genericRecords, readOutput(partitions.get(keyToRecordsEntry.getKey()).getLocation()));
}
}
});
}
use of org.apache.tephra.TransactionAware in project cdap by caskdata.
the class AbstractTransactionContext method checkpoint.
@Override
public void checkpoint() throws TransactionFailureException {
Preconditions.checkState(currentTx != null, "Cannot checkpoint tx that has not been started");
persist();
try {
currentTx = txClient.checkpoint(currentTx);
// update the current transaction with all TransactionAwares
for (TransactionAware txAware : getTransactionAwares()) {
txAware.updateTx(currentTx);
}
} catch (TransactionFailureException e) {
abort(e);
} catch (Throwable e) {
abort(new TransactionFailureException(String.format("Exception from checkpoint for transaction %d.", currentTx.getTransactionId()), e));
}
}
use of org.apache.tephra.TransactionAware in project cdap by caskdata.
the class QueueTest method testRollback.
@Test(timeout = TIMEOUT_MS)
public void testRollback() throws Exception {
QueueName queueName = QueueName.fromFlowlet(NamespaceId.DEFAULT.getEntityName(), "app", "flow", "flowlet", "queuerollback");
ConsumerConfig consumerConfig = new ConsumerConfig(0, 0, 1, DequeueStrategy.FIFO, null);
configureGroups(queueName, ImmutableList.of(consumerConfig));
try (QueueProducer producer = queueClientFactory.createProducer(queueName);
QueueConsumer consumer = queueClientFactory.createConsumer(queueName, consumerConfig, 1)) {
TransactionContext txContext = createTxContext(producer, consumer, new TransactionAware() {
boolean canCommit = false;
@Override
public void startTx(Transaction tx) {
}
@Override
public void updateTx(Transaction tx) {
}
@Override
public Collection<byte[]> getTxChanges() {
return ImmutableList.of();
}
@Override
public boolean commitTx() throws Exception {
// Flip-flop between commit success/failure.
boolean res = canCommit;
canCommit = !canCommit;
return res;
}
@Override
public void postTxCommit() {
}
@Override
public boolean rollbackTx() throws Exception {
return true;
}
@Override
public String getTransactionAwareName() {
return "test";
}
});
// First, try to enqueue and commit would fail
txContext.start();
try {
producer.enqueue(new QueueEntry(Bytes.toBytes(1)));
txContext.finish();
// If reaches here, it's wrong, as exception should be thrown.
Assert.assertTrue(false);
} catch (TransactionFailureException e) {
txContext.abort();
}
// Try to enqueue again. Within the same transaction, dequeue should be empty.
txContext.start();
producer.enqueue(new QueueEntry(Bytes.toBytes(1)));
Assert.assertTrue(consumer.dequeue().isEmpty());
txContext.finish();
// This time, enqueue has been committed, dequeue would see the item
txContext.start();
try {
Assert.assertEquals(1, Bytes.toInt(consumer.dequeue().iterator().next()));
txContext.finish();
// If reaches here, it's wrong, as exception should be thrown.
Assert.assertTrue(false);
} catch (TransactionFailureException e) {
txContext.abort();
}
// Dequeue again, since last tx was rollback, this dequeue should see the item again.
txContext.start();
Assert.assertEquals(1, Bytes.toInt(consumer.dequeue().iterator().next()));
txContext.finish();
}
}
use of org.apache.tephra.TransactionAware in project cdap by caskdata.
the class HBaseQueueTest method testReconfigure.
@Test(timeout = 30000L)
public void testReconfigure() throws Exception {
final QueueName queueName = QueueName.fromFlowlet(NamespaceId.DEFAULT.getEntityName(), "app", "flow", "flowlet", "changeinstances");
ConsumerGroupConfig groupConfig = new ConsumerGroupConfig(0L, 2, DequeueStrategy.HASH, "key");
configureGroups(queueName, ImmutableList.of(groupConfig));
// Enqueue 10 items
createEnqueueRunnable(queueName, 10, 1, null).run();
// Map from instance id to items dequeued
final Multimap<Integer, Integer> dequeued = ArrayListMultimap.create();
// Consume 2 items for each consumer instances
for (int instanceId = 0; instanceId < groupConfig.getGroupSize(); instanceId++) {
final ConsumerConfig consumerConfig = new ConsumerConfig(groupConfig, instanceId);
try (QueueConsumer consumer = queueClientFactory.createConsumer(queueName, consumerConfig, 1)) {
Transactions.createTransactionExecutor(executorFactory, (TransactionAware) consumer).execute(new TransactionExecutor.Subroutine() {
@Override
public void apply() throws Exception {
DequeueResult<byte[]> result = consumer.dequeue(2);
Assert.assertEquals(2, result.size());
for (byte[] data : result) {
dequeued.put(consumerConfig.getInstanceId(), Bytes.toInt(data));
}
}
});
}
}
// Increase number of instances to 3
changeInstances(queueName, 0L, 3);
// Enqueue 10 more items
createEnqueueRunnable(queueName, 10, 1, null).run();
groupConfig = new ConsumerGroupConfig(0L, 3, DequeueStrategy.HASH, "key");
// Dequeue everything
while (dequeued.size() != 20) {
for (int instanceId = 0; instanceId < groupConfig.getGroupSize(); instanceId++) {
final ConsumerConfig consumerConfig = new ConsumerConfig(groupConfig, instanceId);
try (QueueConsumer consumer = queueClientFactory.createConsumer(queueName, consumerConfig, 1)) {
Transactions.createTransactionExecutor(executorFactory, (TransactionAware) consumer).execute(new TransactionExecutor.Subroutine() {
@Override
public void apply() throws Exception {
for (byte[] data : consumer.dequeue(20)) {
dequeued.put(consumerConfig.getInstanceId(), Bytes.toInt(data));
}
}
});
}
}
}
// Instance 0 should see all evens before change instances
Assert.assertEquals(ImmutableList.of(0, 2, 4, 6, 8, 0, 3, 6, 9), dequeued.get(0));
// Instance 1 should see all odds before change instances
Assert.assertEquals(ImmutableList.of(1, 3, 5, 7, 9, 1, 4, 7), dequeued.get(1));
// Instance 2 should only see entries after change instances
Assert.assertEquals(ImmutableList.of(2, 5, 8), dequeued.get(2));
// All consumers should have empty dequeue now
for (int instanceId = 0; instanceId < groupConfig.getGroupSize(); instanceId++) {
final ConsumerConfig consumerConfig = new ConsumerConfig(groupConfig, instanceId);
try (QueueConsumer consumer = queueClientFactory.createConsumer(queueName, consumerConfig, 1)) {
Transactions.createTransactionExecutor(executorFactory, (TransactionAware) consumer).execute(new TransactionExecutor.Subroutine() {
@Override
public void apply() throws Exception {
DequeueResult<byte[]> result = consumer.dequeue(20);
Assert.assertTrue(result.isEmpty());
}
});
}
}
// Enqueue 6 more items for the 3 instances
createEnqueueRunnable(queueName, 6, 1, null).run();
// Reduce to 1 consumer
changeInstances(queueName, 0L, 1);
// The consumer 0 should be able to consume all 10 new items
dequeued.clear();
final ConsumerConfig consumerConfig = new ConsumerConfig(0L, 0, 1, DequeueStrategy.HASH, "key");
try (final QueueConsumer consumer = queueClientFactory.createConsumer(queueName, consumerConfig, 1)) {
while (dequeued.size() != 6) {
Transactions.createTransactionExecutor(executorFactory, (TransactionAware) consumer).execute(new TransactionExecutor.Subroutine() {
@Override
public void apply() throws Exception {
for (byte[] data : consumer.dequeue(1)) {
dequeued.put(consumerConfig.getInstanceId(), Bytes.toInt(data));
}
}
});
}
}
Assert.assertEquals(ImmutableList.of(0, 1, 2, 3, 4, 5), dequeued.get(0));
}
Aggregations