/* * Copyright © 2015-2016 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.cdap.api.dataset.lib.partitioned; import co.cask.cdap.api.Transactional; import co.cask.cdap.api.TxRunnable; import co.cask.cdap.api.annotation.Beta; import co.cask.cdap.api.data.DatasetContext; import co.cask.cdap.api.dataset.lib.DatasetStatePersistor; import co.cask.cdap.api.dataset.lib.Partition; import co.cask.cdap.api.dataset.lib.PartitionKey; import co.cask.cdap.api.dataset.lib.PartitionedFileSet; import co.cask.tephra.TransactionFailureException; import java.util.List; import java.util.concurrent.atomic.AtomicReference; /** * An implementation of {@link PartitionConsumer} that uses a {@link Transactional} to execute its methods * in a new transaction. For each call to the methods it implements, it starts its own, new transaction. */ @Beta public final class TransactionalPartitionConsumer implements PartitionConsumer { private final Transactional transactional; private final ConsumerConfiguration consumerConfiguration; private final String partitionedFileSetName; private final DatasetStatePersistor statePersistor; /** * @param transactional object used to start the new transactions * @param partitionedFileSetName the name of the {@link PartitionedFileSet} to consume partitions from * @param statePersistor a {@link DatasetStatePersistor} responsible for defining how the partition consumer state is * managed */ public TransactionalPartitionConsumer(Transactional transactional, String partitionedFileSetName, DatasetStatePersistor statePersistor) { this(transactional, partitionedFileSetName, statePersistor, ConsumerConfiguration.DEFAULT); } /** * @param transactional object used to start the new transactions * @param partitionedFileSetName the name of the {@link PartitionedFileSet} to consume partitions from * @param statePersistor a {@link DatasetStatePersistor} responsible for defining how the partition consumer state is * managed * @param consumerConfiguration defines parameters for the partition consumption */ public TransactionalPartitionConsumer(Transactional transactional, String partitionedFileSetName, DatasetStatePersistor statePersistor, ConsumerConfiguration consumerConfiguration) { this.transactional = transactional; this.partitionedFileSetName = partitionedFileSetName; this.statePersistor = statePersistor; this.consumerConfiguration = consumerConfiguration; } @Override public PartitionConsumerResult consumePartitions() { return consumePartitions(Integer.MAX_VALUE); } @Override public PartitionConsumerResult consumePartitions(final int limit) { return consumePartitions(new PartitionAcceptor.Limit(limit)); } @Override public PartitionConsumerResult consumePartitions(final PartitionAcceptor acceptor) { final AtomicReference<PartitionConsumerResult> partitions = new AtomicReference<>(); try { transactional.execute(new TxRunnable() { @Override public void run(DatasetContext context) throws Exception { partitions.set(getPartitionConsumer(context).consumePartitions(acceptor)); } }); } catch (TransactionFailureException e) { throw new RuntimeException(e); } return partitions.get(); } @Override public void onFinish(final List<? extends Partition> partitions, final boolean succeeded) { try { transactional.execute(new TxRunnable() { @Override public void run(DatasetContext context) throws Exception { getPartitionConsumer(context).onFinish(partitions, succeeded); } }); } catch (TransactionFailureException e) { throw new RuntimeException(e); } } @Override public void onFinishWithKeys(final List<? extends PartitionKey> partitionKeys, final boolean succeeded) { try { transactional.execute(new TxRunnable() { @Override public void run(DatasetContext context) throws Exception { getPartitionConsumer(context).onFinishWithKeys(partitionKeys, succeeded); } }); } catch (TransactionFailureException e) { throw new RuntimeException(e); } } private PartitionConsumer getPartitionConsumer(DatasetContext context) { PartitionedFileSet lines = context.getDataset(partitionedFileSetName); return new ConcurrentPartitionConsumer(lines, new DelegatingStatePersistor(context, statePersistor), consumerConfiguration); } }