| /* |
| * 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.dht; |
| |
| import java.io.DataInput; |
| import java.io.IOException; |
| import java.io.Serializable; |
| import java.util.*; |
| |
| import org.apache.cassandra.db.DecoratedKey; |
| import org.apache.cassandra.db.TypeSizes; |
| import org.apache.cassandra.db.RowPosition; |
| import org.apache.cassandra.db.marshal.AbstractType; |
| import org.apache.cassandra.io.IVersionedSerializer; |
| import org.apache.cassandra.io.util.DataOutputPlus; |
| import org.apache.cassandra.utils.Pair; |
| |
| public abstract class AbstractBounds<T extends RingPosition> implements Serializable |
| { |
| private static final long serialVersionUID = 1L; |
| public static final AbstractBoundsSerializer serializer = new AbstractBoundsSerializer(); |
| |
| private enum Type |
| { |
| RANGE, |
| BOUNDS |
| } |
| |
| public final T left; |
| public final T right; |
| |
| protected transient final IPartitioner partitioner; |
| |
| public AbstractBounds(T left, T right, IPartitioner partitioner) |
| { |
| this.left = left; |
| this.right = right; |
| this.partitioner = partitioner; |
| } |
| |
| /** |
| * Given token T and AbstractBounds ?L,R?, returns Pair(?L,T], (T,R?), |
| * where ? means that the same type of AbstractBounds is returned as the original. |
| * |
| * Put another way, returns a Pair of everything this AbstractBounds contains |
| * up to and including the split position, and everything it contains after |
| * (not including the split position). |
| * |
| * The original AbstractBounds must either contain the position T, or T |
| * should be equals to the left bound L. |
| * |
| * If the split would only yield the same AbstractBound, null is returned |
| * instead. |
| */ |
| public abstract Pair<AbstractBounds<T>, AbstractBounds<T>> split(T position); |
| |
| @Override |
| public int hashCode() |
| { |
| return 31 * left.hashCode() + right.hashCode(); |
| } |
| |
| /** return true if @param range intersects any of the given @param ranges */ |
| public boolean intersects(Iterable<Range<T>> ranges) |
| { |
| for (Range<T> range2 : ranges) |
| { |
| if (range2.intersects(this)) |
| return true; |
| } |
| return false; |
| } |
| |
| public abstract boolean contains(T start); |
| |
| public abstract List<? extends AbstractBounds<T>> unwrap(); |
| |
| public String getString(AbstractType<?> keyValidator) |
| { |
| return getOpeningString() + format(left, keyValidator) + ", " + format(right, keyValidator) + getClosingString(); |
| } |
| |
| private String format(T value, AbstractType<?> keyValidator) |
| { |
| if (value instanceof DecoratedKey) |
| { |
| return keyValidator.getString(((DecoratedKey)value).getKey()); |
| } |
| else |
| { |
| return value.toString(); |
| } |
| } |
| |
| protected abstract String getOpeningString(); |
| protected abstract String getClosingString(); |
| |
| /** |
| * Transform this abstract bounds to equivalent covering bounds of row positions. |
| * If this abstract bounds was already an abstractBounds of row positions, this is a noop. |
| */ |
| public abstract AbstractBounds<RowPosition> toRowBounds(); |
| |
| /** |
| * Transform this abstract bounds to a token abstract bounds. |
| * If this abstract bounds was already an abstractBounds of token, this is a noop, otherwise this use the row position tokens. |
| */ |
| public abstract AbstractBounds<Token> toTokenBounds(); |
| |
| public abstract AbstractBounds<T> withNewRight(T newRight); |
| |
| public static class AbstractBoundsSerializer implements IVersionedSerializer<AbstractBounds<?>> |
| { |
| public void serialize(AbstractBounds<?> range, DataOutputPlus out, int version) throws IOException |
| { |
| /* |
| * The first int tells us if it's a range or bounds (depending on the value) _and_ if it's tokens or keys (depending on the |
| * sign). We use negative kind for keys so as to preserve the serialization of token from older version. |
| */ |
| out.writeInt(kindInt(range)); |
| if (range.left instanceof Token) |
| { |
| Token.serializer.serialize((Token) range.left, out); |
| Token.serializer.serialize((Token) range.right, out); |
| } |
| else |
| { |
| RowPosition.serializer.serialize((RowPosition) range.left, out); |
| RowPosition.serializer.serialize((RowPosition) range.right, out); |
| } |
| } |
| |
| private int kindInt(AbstractBounds<?> ab) |
| { |
| int kind = ab instanceof Range ? Type.RANGE.ordinal() : Type.BOUNDS.ordinal(); |
| if (!(ab.left instanceof Token)) |
| kind = -(kind + 1); |
| return kind; |
| } |
| |
| public AbstractBounds<?> deserialize(DataInput in, int version) throws IOException |
| { |
| int kind = in.readInt(); |
| boolean isToken = kind >= 0; |
| if (!isToken) |
| kind = -(kind+1); |
| |
| RingPosition left, right; |
| if (isToken) |
| { |
| left = Token.serializer.deserialize(in); |
| right = Token.serializer.deserialize(in); |
| } |
| else |
| { |
| left = RowPosition.serializer.deserialize(in); |
| right = RowPosition.serializer.deserialize(in); |
| } |
| |
| if (kind == Type.RANGE.ordinal()) |
| return new Range(left, right); |
| return new Bounds(left, right); |
| } |
| |
| public long serializedSize(AbstractBounds<?> ab, int version) |
| { |
| int size = TypeSizes.NATIVE.sizeof(kindInt(ab)); |
| if (ab.left instanceof Token) |
| { |
| size += Token.serializer.serializedSize((Token) ab.left, TypeSizes.NATIVE); |
| size += Token.serializer.serializedSize((Token) ab.right, TypeSizes.NATIVE); |
| } |
| else |
| { |
| size += RowPosition.serializer.serializedSize((RowPosition) ab.left, TypeSizes.NATIVE); |
| size += RowPosition.serializer.serializedSize((RowPosition) ab.right, TypeSizes.NATIVE); |
| } |
| return size; |
| } |
| } |
| } |