/*
* 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.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.apache.cassandra.dht.*;
import org.apache.cassandra.io.ISerializer;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.ByteBufferUtil;
public abstract class RowPosition implements RingPosition<RowPosition>
{
public static enum Kind
{
// Only add new values to the end of the enum, the ordinal is used
// during serialization
ROW_KEY, MIN_BOUND, MAX_BOUND;
private static final Kind[] allKinds = Kind.values();
static Kind fromOrdinal(int ordinal)
{
return allKinds[ordinal];
}
}
public static final RowPositionSerializer serializer = new RowPositionSerializer();
public static RowPosition forKey(ByteBuffer key, IPartitioner p)
{
return key == null || key.remaining() == 0 ? p.getMinimumToken().minKeyBound() : p.decorateKey(key);
}
public abstract Token getToken();
public abstract Kind kind();
public boolean isMinimum()
{
return isMinimum(StorageService.getPartitioner());
}
public static class RowPositionSerializer implements ISerializer<RowPosition>
{
/*
* We need to be able to serialize both Token.KeyBound and
* DecoratedKey. To make this compact, we first write a byte whose
* meaning is:
* - 0: DecoratedKey
* - 1: a 'minimum' Token.KeyBound
* - 2: a 'maximum' Token.KeyBound
* In the case of the DecoratedKey, we then serialize the key (the
* token is recreated on the other side). In the other cases, we then
* serialize the token.
*/
public void serialize(RowPosition pos, DataOutput out) throws IOException
{
Kind kind = pos.kind();
out.writeByte(kind.ordinal());
if (kind == Kind.ROW_KEY)
ByteBufferUtil.writeWithShortLength(((DecoratedKey)pos).key, out);
else
Token.serializer.serialize(pos.getToken(), out);
}
public RowPosition deserialize(DataInput in) throws IOException
{
Kind kind = Kind.fromOrdinal(in.readByte());
if (kind == Kind.ROW_KEY)
{
ByteBuffer k = ByteBufferUtil.readWithShortLength(in);
return StorageService.getPartitioner().decorateKey(k);
}
else
{
Token t = Token.serializer.deserialize(in);
return kind == Kind.MIN_BOUND ? t.minKeyBound() : t.maxKeyBound();
}
}
public long serializedSize(RowPosition pos, TypeSizes typeSizes)
{
Kind kind = pos.kind();
int size = 1; // 1 byte for enum
if (kind == Kind.ROW_KEY)
{
int keySize = ((DecoratedKey)pos).key.remaining();
size += typeSizes.sizeof((short) keySize) + keySize;
}
else
{
size += Token.serializer.serializedSize(pos.getToken(), typeSizes);
}
return size;
}
}
}