/* * 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.dataset.lib.Partition; import co.cask.cdap.api.dataset.lib.PartitionKey; import co.cask.cdap.api.dataset.lib.PartitionedFileSet; import java.util.AbstractList; import java.util.List; /** * Abstract implementation of PartitionConsumer, which manages state persistence and serialization/deserialization * before delegating to the abstract methods. */ public abstract class AbstractPartitionConsumer implements PartitionConsumer { private final PartitionedFileSet partitionedFileSet; private final ConsumerConfiguration configuration; private final StatePersistor statePersistor; /** * This method will be called whenever a {@link PartitionConsumer} requests partitions, to consume partitions * from the working set, while marking them as IN_PROGRESS * * @param acceptor a {@link PartitionAcceptor} which defines which partitions to accept/consume * @return a {@link PartitionConsumerResult} representing the consumed partitions */ public abstract PartitionConsumerResult doConsume(ConsumerWorkingSet workingSet, PartitionAcceptor acceptor); /** * This method will be called on any partitions returned by the {@code #consumePartitions} method. * * @param workingSet the working set of partitions to operate on * @param partitionKeys list of partition keys to mark as either succeeded or failed processing * @param succeeded whether or not processing of the specified partitions was successful */ public abstract void doFinish(ConsumerWorkingSet workingSet, List<? extends PartitionKey> partitionKeys, boolean succeeded); /** * Creates an instance of PartitionConsumer. * * @param partitionedFileSet the PartitionedFileSet to consume from * @param statePersistor defines how the state of the PartitionConsumer will be maintained */ public AbstractPartitionConsumer(PartitionedFileSet partitionedFileSet, StatePersistor statePersistor) { this(partitionedFileSet, statePersistor, ConsumerConfiguration.DEFAULT); } /** * Creates an instance of PartitionConsumer. * * @param partitionedFileSet the PartitionedFileSet to consume from * @param statePersistor defines how the state of the PartitionConsumer will be maintained * @param configuration the PartitionedConsumerConfiguration, defining parameters of consumption */ public AbstractPartitionConsumer(PartitionedFileSet partitionedFileSet, StatePersistor statePersistor, ConsumerConfiguration configuration) { this.partitionedFileSet = partitionedFileSet; this.configuration = configuration; this.statePersistor = statePersistor; } public PartitionedFileSet getPartitionedFileSet() { return partitionedFileSet; } public ConsumerConfiguration getConfiguration() { return configuration; } public StatePersistor getStatePersistor() { return statePersistor; } @Override public PartitionConsumerResult consumePartitions() { return consumePartitions(Integer.MAX_VALUE); } @Override public PartitionConsumerResult consumePartitions(int limit) { return consumePartitions(new PartitionAcceptor.Limit(limit)); } @Override public PartitionConsumerResult consumePartitions(PartitionAcceptor acceptor) { ConsumerWorkingSet workingSet = readState(); PartitionConsumerResult partitionsResult = doConsume(workingSet, acceptor); statePersistor.persistState(workingSet.toBytes()); return partitionsResult; } @Override public void onFinish(final List<? extends Partition> partitions, boolean succeeded) { List<PartitionKey> partitionKeys = new AbstractList<PartitionKey>() { @Override public int size() { return partitions.size(); } @Override public PartitionKey get(int index) { return partitions.get(index).getPartitionKey(); } @Override public void clear() { partitions.clear(); } @Override public PartitionKey remove(int index) { return partitions.remove(index).getPartitionKey(); } }; onFinishWithKeys(partitionKeys, succeeded); } @Override public void onFinishWithKeys(List<? extends PartitionKey> partitionKeys, boolean succeeded) { ConsumerWorkingSet workingSet = readState(); doFinish(workingSet, partitionKeys, succeeded); statePersistor.persistState(workingSet.toBytes()); } private ConsumerWorkingSet readState() { byte[] bytes = statePersistor.readState(); return bytes == null ? new ConsumerWorkingSet() : ConsumerWorkingSet.fromBytes(bytes); } }