/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.cassandra.db.transform; import org.apache.cassandra.db.DeletionTime; import org.apache.cassandra.db.partitions.PartitionIterator; import org.apache.cassandra.db.partitions.UnfilteredPartitionIterator; import org.apache.cassandra.db.rows.*; /** * We have a single common superclass for all Transformations to make implementation efficient. * we have a shared stack for all transformations, and can share the same transformation across partition and row * iterators, reducing garbage. Internal code is also simplified by always having a basic no-op implementation to invoke. * * Only the necessary methods need be overridden. Early termination is provided by invoking the method's stop or stopInPartition * methods, rather than having their own abstract method to invoke, as this is both more efficient and simpler to reason about. */ public abstract class Transformation<I extends BaseRowIterator<?>> { // internal methods for StoppableTransformation only void attachTo(BasePartitions partitions) { } void attachTo(BaseRows rows) { } /** * Run on the close of any (logical) partitions iterator this function was applied to * * We stipulate logical, because if applied to a transformed iterator the lifetime of the iterator * object may be longer than the lifetime of the "logical" iterator it was applied to; if the iterator * is refilled with MoreContents, for instance, the iterator may outlive this function */ protected void onClose() { } /** * Run on the close of any (logical) rows iterator this function was applied to * * We stipulate logical, because if applied to a transformed iterator the lifetime of the iterator * object may be longer than the lifetime of the "logical" iterator it was applied to; if the iterator * is refilled with MoreContents, for instance, the iterator may outlive this function */ protected void onPartitionClose() { } /** * Applied to any rows iterator (partition) we encounter in a partitions iterator */ protected I applyToPartition(I partition) { return partition; } /** * Applied to any row we encounter in a rows iterator */ protected Row applyToRow(Row row) { return row; } /** * Applied to any RTM we encounter in a rows/unfiltered iterator */ protected RangeTombstoneMarker applyToMarker(RangeTombstoneMarker marker) { return marker; } /** * Applied to the static row of any rows iterator. * * NOTE that this is only applied to the first iterator in any sequence of iterators filled by a MoreContents; * the static data for such iterators is all expected to be equal */ protected Row applyToStatic(Row row) { return row; } /** * Applied to the partition-level deletion of any rows iterator. * * NOTE that this is only applied to the first iterator in any sequence of iterators filled by a MoreContents; * the static data for such iterators is all expected to be equal */ protected DeletionTime applyToDeletion(DeletionTime deletionTime) { return deletionTime; } //****************************************************** // Static Application Methods //****************************************************** public static UnfilteredPartitionIterator apply(UnfilteredPartitionIterator iterator, Transformation<? super UnfilteredRowIterator> transformation) { return add(mutable(iterator), transformation); } public static PartitionIterator apply(PartitionIterator iterator, Transformation<? super RowIterator> transformation) { return add(mutable(iterator), transformation); } public static UnfilteredRowIterator apply(UnfilteredRowIterator iterator, Transformation<?> transformation) { return add(mutable(iterator), transformation); } public static RowIterator apply(RowIterator iterator, Transformation<?> transformation) { return add(mutable(iterator), transformation); } static UnfilteredPartitions mutable(UnfilteredPartitionIterator iterator) { return iterator instanceof UnfilteredPartitions ? (UnfilteredPartitions) iterator : new UnfilteredPartitions(iterator); } static FilteredPartitions mutable(PartitionIterator iterator) { return iterator instanceof FilteredPartitions ? (FilteredPartitions) iterator : new FilteredPartitions(iterator); } static UnfilteredRows mutable(UnfilteredRowIterator iterator) { return iterator instanceof UnfilteredRows ? (UnfilteredRows) iterator : new UnfilteredRows(iterator); } static FilteredRows mutable(RowIterator iterator) { return iterator instanceof FilteredRows ? (FilteredRows) iterator : new FilteredRows(iterator); } static <E extends BaseIterator> E add(E to, Transformation add) { to.add(add); return to; } static <E extends BaseIterator> E add(E to, MoreContents add) { to.add(add); return to; } }