| /* |
| * 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.rows; |
| |
| import java.nio.ByteBuffer; |
| import java.util.Objects; |
| |
| import org.apache.cassandra.db.marshal.ValueAccessor; |
| import org.apache.cassandra.schema.TableMetadata; |
| import org.apache.cassandra.db.*; |
| import org.apache.cassandra.utils.memory.ByteBufferCloner; |
| |
| /** |
| * A range tombstone marker that represents a boundary between 2 range tombstones (i.e. it closes one range and open another). |
| */ |
| public class RangeTombstoneBoundaryMarker extends AbstractRangeTombstoneMarker<ClusteringBoundary<?>> |
| { |
| private final DeletionTime endDeletion; |
| private final DeletionTime startDeletion; |
| |
| public RangeTombstoneBoundaryMarker(ClusteringBoundary<?> bound, DeletionTime endDeletion, DeletionTime startDeletion) |
| { |
| super(bound); |
| assert bound.isBoundary(); |
| this.endDeletion = endDeletion; |
| this.startDeletion = startDeletion; |
| } |
| |
| public static <V> RangeTombstoneBoundaryMarker exclusiveCloseInclusiveOpen(boolean reversed, |
| V[] boundValues, |
| ValueAccessor<V> accessor, |
| DeletionTime closeDeletion, |
| DeletionTime openDeletion) |
| { |
| ClusteringBoundary<V> bound = accessor.factory().exclusiveCloseInclusiveOpen(reversed, boundValues); |
| DeletionTime endDeletion = reversed ? openDeletion : closeDeletion; |
| DeletionTime startDeletion = reversed ? closeDeletion : openDeletion; |
| return new RangeTombstoneBoundaryMarker(bound, endDeletion, startDeletion); |
| } |
| |
| public static <V> RangeTombstoneBoundaryMarker exclusiveCloseInclusiveOpen(boolean reversed, |
| ClusteringPrefix<V> from, |
| DeletionTime closeDeletion, |
| DeletionTime openDeletion) |
| { |
| return exclusiveCloseInclusiveOpen(reversed, from.getRawValues(), from.accessor(), closeDeletion, openDeletion); |
| } |
| |
| public static <V> RangeTombstoneBoundaryMarker inclusiveCloseExclusiveOpen(boolean reversed, |
| V[] boundValues, |
| ValueAccessor<V> accessor, |
| DeletionTime closeDeletion, |
| DeletionTime openDeletion) |
| { |
| ClusteringBoundary<V> bound = accessor.factory().inclusiveCloseExclusiveOpen(reversed, boundValues); |
| DeletionTime endDeletion = reversed ? openDeletion : closeDeletion; |
| DeletionTime startDeletion = reversed ? closeDeletion : openDeletion; |
| return new RangeTombstoneBoundaryMarker(bound, endDeletion, startDeletion); |
| } |
| |
| |
| public static <V> RangeTombstoneBoundaryMarker inclusiveCloseExclusiveOpen(boolean reversed, |
| ClusteringPrefix<V> from, |
| DeletionTime closeDeletion, |
| DeletionTime openDeletion) |
| { |
| return inclusiveCloseExclusiveOpen(reversed, from.getRawValues(), from.accessor(), closeDeletion, openDeletion); |
| } |
| |
| /** |
| * The deletion time for the range tombstone this boundary ends (in clustering order). |
| */ |
| public DeletionTime endDeletionTime() |
| { |
| return endDeletion; |
| } |
| |
| /** |
| * The deletion time for the range tombstone this boundary starts (in clustering order). |
| */ |
| public DeletionTime startDeletionTime() |
| { |
| return startDeletion; |
| } |
| |
| public DeletionTime closeDeletionTime(boolean reversed) |
| { |
| return reversed ? startDeletion : endDeletion; |
| } |
| |
| public DeletionTime openDeletionTime(boolean reversed) |
| { |
| return reversed ? endDeletion : startDeletion; |
| } |
| |
| public boolean openIsInclusive(boolean reversed) |
| { |
| return (bound.kind() == ClusteringPrefix.Kind.EXCL_END_INCL_START_BOUNDARY) ^ reversed; |
| } |
| |
| public ClusteringBound<?> openBound(boolean reversed) |
| { |
| return bound.openBound(reversed); |
| } |
| |
| public ClusteringBound<?> closeBound(boolean reversed) |
| { |
| return bound.closeBound(reversed); |
| } |
| |
| public boolean closeIsInclusive(boolean reversed) |
| { |
| return (bound.kind() == ClusteringPrefix.Kind.INCL_END_EXCL_START_BOUNDARY) ^ reversed; |
| } |
| |
| public boolean isOpen(boolean reversed) |
| { |
| // A boundary always open one side |
| return true; |
| } |
| |
| public boolean isClose(boolean reversed) |
| { |
| // A boundary always close one side |
| return true; |
| } |
| |
| public boolean hasInvalidDeletions() |
| { |
| return !startDeletion.validate() || !endDeletion.validate(); |
| } |
| |
| @Override |
| public RangeTombstoneBoundaryMarker clone(ByteBufferCloner cloner) |
| { |
| return new RangeTombstoneBoundaryMarker((ClusteringBoundary<ByteBuffer>) clustering().clone(cloner), endDeletion, startDeletion); |
| } |
| |
| public RangeTombstoneBoundaryMarker withNewOpeningDeletionTime(boolean reversed, DeletionTime newDeletionTime) |
| { |
| return new RangeTombstoneBoundaryMarker(clustering(), |
| reversed ? newDeletionTime : endDeletion, |
| reversed ? startDeletion : newDeletionTime); |
| } |
| |
| public static <V1, V2> RangeTombstoneBoundaryMarker makeBoundary(boolean reversed, |
| ClusteringBound<V1> close, |
| ClusteringBound<V2> open, |
| DeletionTime closeDeletion, |
| DeletionTime openDeletion) |
| { |
| assert ClusteringPrefix.Kind.compare(close.kind(), open.kind()) == 0 : "Both bound don't form a boundary"; |
| boolean isExclusiveClose = close.isExclusive() || (close.isInclusive() && open.isInclusive() && openDeletion.supersedes(closeDeletion)); |
| return isExclusiveClose |
| ? exclusiveCloseInclusiveOpen(reversed, close.getRawValues(), close.accessor(), closeDeletion, openDeletion) |
| : inclusiveCloseExclusiveOpen(reversed, close.getRawValues(), close.accessor(), closeDeletion, openDeletion); |
| } |
| |
| public RangeTombstoneBoundMarker createCorrespondingCloseMarker(boolean reversed) |
| { |
| return new RangeTombstoneBoundMarker(closeBound(reversed), closeDeletionTime(reversed)); |
| } |
| |
| public RangeTombstoneBoundMarker createCorrespondingOpenMarker(boolean reversed) |
| { |
| return new RangeTombstoneBoundMarker(openBound(reversed), openDeletionTime(reversed)); |
| } |
| |
| public void digest(Digest digest) |
| { |
| bound.digest(digest); |
| endDeletion.digest(digest); |
| startDeletion.digest(digest); |
| } |
| |
| public String toString(TableMetadata metadata) |
| { |
| return String.format("Marker %s@%d/%d-%d/%d", |
| bound.toString(metadata), |
| endDeletion.markedForDeleteAt(), endDeletion.localDeletionTime(), |
| startDeletion.markedForDeleteAt(), startDeletion.localDeletionTime()); |
| } |
| |
| @Override |
| public boolean equals(Object other) |
| { |
| if(!(other instanceof RangeTombstoneBoundaryMarker)) |
| return false; |
| |
| RangeTombstoneBoundaryMarker that = (RangeTombstoneBoundaryMarker)other; |
| return this.bound.equals(that.bound) |
| && this.endDeletion.equals(that.endDeletion) |
| && this.startDeletion.equals(that.startDeletion); |
| } |
| |
| @Override |
| public int hashCode() |
| { |
| return Objects.hash(bound, endDeletion, startDeletion); |
| } |
| } |