/*
 * 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.security.MessageDigest;
import java.util.Objects;
import java.util.Set;

import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.db.*;
import org.apache.cassandra.utils.memory.AbstractAllocator;

A range tombstone marker that represents a boundary between 2 range tombstones (i.e. it closes one range and open another).
/** * 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 RangeTombstoneBoundaryMarker exclusiveCloseInclusiveOpen(boolean reversed, ByteBuffer[] boundValues, DeletionTime closeDeletion, DeletionTime openDeletion) { ClusteringBoundary bound = ClusteringBoundary.exclusiveCloseInclusiveOpen(reversed, boundValues); DeletionTime endDeletion = reversed ? openDeletion : closeDeletion; DeletionTime startDeletion = reversed ? closeDeletion : openDeletion; return new RangeTombstoneBoundaryMarker(bound, endDeletion, startDeletion); } public static RangeTombstoneBoundaryMarker inclusiveCloseExclusiveOpen(boolean reversed, ByteBuffer[] boundValues, DeletionTime closeDeletion, DeletionTime openDeletion) { ClusteringBoundary bound = ClusteringBoundary.inclusiveCloseExclusiveOpen(reversed, boundValues); DeletionTime endDeletion = reversed ? openDeletion : closeDeletion; DeletionTime startDeletion = reversed ? closeDeletion : openDeletion; return new RangeTombstoneBoundaryMarker(bound, endDeletion, startDeletion); }
The deletion time for the range tombstone this boundary ends (in clustering order).
/** * 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).
/** * 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 RangeTombstoneBoundaryMarker copy(AbstractAllocator allocator) { return new RangeTombstoneBoundaryMarker(clustering().copy(allocator), endDeletion, startDeletion); } public RangeTombstoneBoundaryMarker withNewOpeningDeletionTime(boolean reversed, DeletionTime newDeletionTime) { return new RangeTombstoneBoundaryMarker(clustering(), reversed ? newDeletionTime : endDeletion, reversed ? startDeletion : newDeletionTime); } public static RangeTombstoneBoundaryMarker makeBoundary(boolean reversed, ClusteringBound close, ClusteringBound 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(), closeDeletion, openDeletion) : inclusiveCloseExclusiveOpen(reversed, close.getRawValues(), 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(MessageDigest digest) { bound.digest(digest); endDeletion.digest(digest); startDeletion.digest(digest); } @Override public void digest(MessageDigest digest, Set<ByteBuffer> columnsToExclude) { digest(digest); } public String toString(CFMetaData 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); } }