All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.cassandra.db.RangeTombstone Maven / Gradle / Ivy

Go to download

The Apache Cassandra Project develops a highly scalable second-generation distributed database, bringing together Dynamo's fully distributed design and Bigtable's ColumnFamily-based data model.

There is a newer version: 5.0.2
Show newest version
/*
 * 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;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Objects;

import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.rows.RangeTombstoneMarker;
import org.apache.cassandra.io.util.DataInputPlus;
import org.apache.cassandra.io.util.DataOutputPlus;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.memory.AbstractAllocator;


/**
 * A range tombstone is a tombstone that covers a slice/range of rows.
 * 

* Note that in most of the storage engine, a range tombstone is actually represented by its separated * opening and closing bound, see {@link RangeTombstoneMarker}. So in practice, this is only used when * full partitions are materialized in memory in a {@code Partition} object, and more precisely through * the use of a {@code RangeTombstoneList} in a {@code DeletionInfo} object. */ public class RangeTombstone { private final Slice slice; private final DeletionTime deletion; public RangeTombstone(Slice slice, DeletionTime deletion) { this.slice = slice; this.deletion = deletion; } /** * The slice of rows that is deleted by this range tombstone. * * @return the slice of rows that is deleted by this range tombstone. */ public Slice deletedSlice() { return slice; } /** * The deletion time for this (range) tombstone. * * @return the deletion time for this range tombstone. */ public DeletionTime deletionTime() { return deletion; } public String toString(ClusteringComparator comparator) { return slice.toString(comparator) + '@' + deletion; } @Override public boolean equals(Object other) { if(!(other instanceof RangeTombstone)) return false; RangeTombstone that = (RangeTombstone)other; return this.deletedSlice().equals(that.deletedSlice()) && this.deletionTime().equals(that.deletionTime()); } @Override public int hashCode() { return Objects.hash(deletedSlice(), deletionTime()); } /** * The bound of a range tombstone. *

* This is the same than for a slice but it includes "boundaries" between ranges. A boundary simply condensed * a close and an opening "bound" into a single object. There is 2 main reasons for these "shortcut" boundaries: * 1) When merging multiple iterators having range tombstones (that are represented by their start and end markers), * we need to know when a range is close on an iterator, if it is reopened right away. Otherwise, we cannot * easily produce the markers on the merged iterators within risking to fail the sorting guarantees of an * iterator. See this comment for more details: https://goo.gl/yyB5mR. * 2) This saves some storage space. */ public static class Bound extends Slice.Bound { public static final Serializer serializer = new Serializer(); /** The smallest start bound, i.e. the one that starts before any row. */ public static final Bound BOTTOM = new Bound(Kind.INCL_START_BOUND, EMPTY_VALUES_ARRAY); /** The biggest end bound, i.e. the one that ends after any row. */ public static final Bound TOP = new Bound(Kind.INCL_END_BOUND, EMPTY_VALUES_ARRAY); public Bound(Kind kind, ByteBuffer[] values) { super(kind, values); assert values.length > 0 || !kind.isBoundary(); } public boolean isBoundary() { return kind.isBoundary(); } public boolean isOpen(boolean reversed) { return kind.isOpen(reversed); } public boolean isClose(boolean reversed) { return kind.isClose(reversed); } public static RangeTombstone.Bound inclusiveOpen(boolean reversed, ByteBuffer[] boundValues) { return new Bound(reversed ? Kind.INCL_END_BOUND : Kind.INCL_START_BOUND, boundValues); } public static RangeTombstone.Bound exclusiveOpen(boolean reversed, ByteBuffer[] boundValues) { return new Bound(reversed ? Kind.EXCL_END_BOUND : Kind.EXCL_START_BOUND, boundValues); } public static RangeTombstone.Bound inclusiveClose(boolean reversed, ByteBuffer[] boundValues) { return new Bound(reversed ? Kind.INCL_START_BOUND : Kind.INCL_END_BOUND, boundValues); } public static RangeTombstone.Bound exclusiveClose(boolean reversed, ByteBuffer[] boundValues) { return new Bound(reversed ? Kind.EXCL_START_BOUND : Kind.EXCL_END_BOUND, boundValues); } public static RangeTombstone.Bound inclusiveCloseExclusiveOpen(boolean reversed, ByteBuffer[] boundValues) { return new Bound(reversed ? Kind.EXCL_END_INCL_START_BOUNDARY : Kind.INCL_END_EXCL_START_BOUNDARY, boundValues); } public static RangeTombstone.Bound exclusiveCloseInclusiveOpen(boolean reversed, ByteBuffer[] boundValues) { return new Bound(reversed ? Kind.INCL_END_EXCL_START_BOUNDARY : Kind.EXCL_END_INCL_START_BOUNDARY, boundValues); } public static RangeTombstone.Bound fromSliceBound(Slice.Bound sliceBound) { return new RangeTombstone.Bound(sliceBound.kind(), sliceBound.getRawValues()); } public RangeTombstone.Bound copy(AbstractAllocator allocator) { ByteBuffer[] newValues = new ByteBuffer[size()]; for (int i = 0; i < size(); i++) newValues[i] = allocator.clone(get(i)); return new Bound(kind(), newValues); } public ClusteringPrefix minimize() { if (!ByteBufferUtil.canMinimize(values)) return this; return new Bound(kind, ByteBufferUtil.minimizeBuffers(values)); } @Override public Bound withNewKind(Kind kind) { return new Bound(kind, values); } public static class Serializer { public void serialize(RangeTombstone.Bound bound, DataOutputPlus out, int version, List> types) throws IOException { out.writeByte(bound.kind().ordinal()); out.writeShort(bound.size()); ClusteringPrefix.serializer.serializeValuesWithoutSize(bound, out, version, types); } public long serializedSize(RangeTombstone.Bound bound, int version, List> types) { return 1 // kind ordinal + TypeSizes.sizeof((short)bound.size()) + ClusteringPrefix.serializer.valuesWithoutSizeSerializedSize(bound, version, types); } public RangeTombstone.Bound deserialize(DataInputPlus in, int version, List> types) throws IOException { Kind kind = Kind.values()[in.readByte()]; return deserializeValues(in, kind, version, types); } public RangeTombstone.Bound deserializeValues(DataInputPlus in, Kind kind, int version, List> types) throws IOException { int size = in.readUnsignedShort(); if (size == 0) return kind.isStart() ? BOTTOM : TOP; ByteBuffer[] values = ClusteringPrefix.serializer.deserializeValuesWithoutSize(in, size, version, types); return new RangeTombstone.Bound(kind, values); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy