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

org.apache.cassandra.db.marshal.ValueAccessor 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.marshal;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

import org.apache.cassandra.db.Clustering;
import org.apache.cassandra.db.ClusteringBound;
import org.apache.cassandra.db.ClusteringBoundOrBoundary;
import org.apache.cassandra.db.ClusteringBoundary;
import org.apache.cassandra.db.ClusteringPrefix;
import org.apache.cassandra.db.Digest;
import org.apache.cassandra.db.TypeSizes;
import org.apache.cassandra.db.rows.Cell;
import org.apache.cassandra.db.rows.CellPath;
import org.apache.cassandra.io.util.DataInputPlus;
import org.apache.cassandra.io.util.DataOutputPlus;
import org.apache.cassandra.schema.ColumnMetadata;

import static org.apache.cassandra.db.ClusteringPrefix.Kind.*;

/**
 * ValueAccessor allows serializers and other code dealing with raw bytes to operate on different backing types
 * (ie: byte arrays, byte buffers, etc) without requiring that the supported backing types share a common type
 * ancestor and without incuring the allocation cost of a wrapper object.
 *
 * A note on byte buffers for implementors: the "value" of a byte buffer is always interpreted as beginning at
 * it's {@link ByteBuffer#position()} and having a length of {@link ByteBuffer#remaining()}. ValueAccessor
 * implementations need to maintain this internally. ValueAccessors should also never modify the state of the
 * byte buffers view (ie: offset, limit). This would also apply to value accessors for simlilar types
 * (ie: netty's ByteBuf}.
 *
 * @param  the backing type
 */
public interface ValueAccessor
{

    /**
     * Creates db objects using the given accessors value type. ObjectFactory instances are meant to be returned
     * by the factory() method of a value accessor.
     * @param  the backing type
     */
    public interface ObjectFactory
    {
        Cell cell(ColumnMetadata column, long timestamp, int ttl, int localDeletionTime, V value, CellPath path);
        Clustering clustering(V... values);
        Clustering clustering();
        ClusteringBound bound(ClusteringPrefix.Kind kind, V... values);
        ClusteringBound bound(ClusteringPrefix.Kind kind);
        ClusteringBoundary boundary(ClusteringPrefix.Kind kind, V... values);
        default ClusteringBoundOrBoundary boundOrBoundary(ClusteringPrefix.Kind kind, V... values)
        {
            return kind.isBoundary() ? boundary(kind, values) : bound(kind, values);
        }

        default ClusteringBound inclusiveOpen(boolean reversed, V[] boundValues)
        {
            return bound(reversed ? INCL_END_BOUND : INCL_START_BOUND, boundValues);
        }

        default ClusteringBound exclusiveOpen(boolean reversed, V[] boundValues)
        {
            return bound(reversed ? EXCL_END_BOUND : EXCL_START_BOUND, boundValues);
        }

        default ClusteringBound inclusiveClose(boolean reversed, V[] boundValues)
        {
            return bound(reversed ? INCL_START_BOUND : INCL_END_BOUND, boundValues);
        }

        default ClusteringBound exclusiveClose(boolean reversed, V[] boundValues)
        {
            return bound(reversed ? EXCL_START_BOUND : EXCL_END_BOUND, boundValues);
        }

        default ClusteringBoundary inclusiveCloseExclusiveOpen(boolean reversed, V[] boundValues)
        {
            return boundary(reversed ? EXCL_END_INCL_START_BOUNDARY : INCL_END_EXCL_START_BOUNDARY, boundValues);
        }

        default ClusteringBoundary exclusiveCloseInclusiveOpen(boolean reversed, V[] boundValues)
        {
            return boundary(reversed ? INCL_END_EXCL_START_BOUNDARY : EXCL_END_INCL_START_BOUNDARY, boundValues);
        }

    }
    /**
     * @return the size of the given value
     */
    int size(V value);

    /** serializes size including a vint length prefix */
    default int sizeWithVIntLength(V value)
    {
        int size = size(value);
        return TypeSizes.sizeofUnsignedVInt(size) + size;
    }

    /** serialized size including a short length prefix */
    default int sizeWithShortLength(V value)
    {
        return 2 + size(value);
    }

    /**
     * @return true if the size of the given value is zero, false otherwise
     */
    default boolean isEmpty(V value)
    {
        return size(value) == 0;
    }

    /**
     * @return the number of bytes remaining in the value from the given offset
     */
    default int sizeFromOffset(V value, int offset)
    {
        return size(value) - offset;
    }

    /**
     * @return true if there are no bytes present after the given offset, false otherwise
     */
    default boolean isEmptyFromOffset(V value, int offset)
    {
        return sizeFromOffset(value, offset) == 0;
    }

    /**
     * allocate an instance of the accessors backing type
     * @param length size of backing typ to allocate
     */
    V[] createArray(int length);

    /**
     * Write the contents of the given value into the a DataOutputPlus
     */
    void write(V value, DataOutputPlus out) throws IOException;

    default void writeWithVIntLength(V value, DataOutputPlus out) throws IOException
    {
        out.writeUnsignedVInt(size(value));
        write(value, out);
    }

    /**
     * Write the contents of the given value into the ByteBuffer
     */
    void write(V value, ByteBuffer out);

    /**
     * copy the {@param size} bytes from the {@param src} value, starting at the offset {@param srcOffset} into
     * the {@param dst} value, starting at the offset {@param dstOffset}, using the accessor {@param dstAccessor}
     * @param  the destination value type
     * @return the number of bytes copied ({@param size})
     */
     int copyTo(V src, int srcOffset, V2 dst, ValueAccessor dstAccessor, int dstOffset, int size);

    /**
     * copies a byte array into this accessors value.
     */
    int copyByteArrayTo(byte[] src, int srcOffset, V dst, int dstOffset, int size);

    /**
     * copies a byte buffer into this accessors value.
     */
    int copyByteBufferTo(ByteBuffer src, int srcOffset, V dst, int dstOffset, int size);

    /**
     * updates {@param digest} with {@param size} bytes from the contents of {@param value} starting
     * at offset {@param offset}
     */
    void digest(V value, int offset, int size, Digest digest);

    /**
     * updates {@param digest} with te contents of {@param value}
     */
    default void digest(V value, Digest digest)
    {
        digest(value, 0, size(value), digest);
    }

    /**
     * Reads a value of {@param length} bytes from {@param in}
     */
    V read(DataInputPlus in, int length) throws IOException;

    /**
     * Returns a value with the contents of {@param input} from {@param offset} to {@param length}.
     *
     * Depending on the accessor implementation, this method may:
     *  * allocate a new {@param } object of {@param length}, and copy data into it
     *  * return a view of {@param input} where changes to one will be reflected in the other
     */
    V slice(V input, int offset, int length);

    /**
     * same as {@link ValueAccessor#slice(Object, int, int)}, except the length is taken from the first
     * 2 bytes from the given offset (and not included in the return value)
     */
    default V sliceWithShortLength(V input, int offset)
    {
        int size = getUnsignedShort(input, offset);
        return slice(input, offset + 2, size);
    }

    /**
     * lexicographically compare {@param left} to {@param right}
     * @param  backing type of
     */
     int compare(V left, VR right, ValueAccessor accessorR);

    /**
     * compare a byte array on the left with a {@param } on the right}
     */
    int compareByteArrayTo(byte[] left, V right);

    /**
     * compare a byte buffer on the left with a {@param } on the right}
     */
    int compareByteBufferTo(ByteBuffer left, V right);

    default int hashCode(V value)
    {
        if (value == null)
            return 0;

        int result = 1;
        for (int i=0, isize=size(value); i}
     *
     * {@param src} and the returned value may share a common byte array instance, so caller should
     * assume that modifying the returned value will also modify the contents of {@param src}
     */
     V convert(V2 src, ValueAccessor accessor);

    /**
     * Allocate and return a {@param } instance of {@param size} bytes on the heap.
     */
    V allocate(int size);

    /**
     * returns the {@link ValueAccessor.ObjectFactory} for the backing type {@param }
     */
    ObjectFactory factory();

    /**
     * lexicographically compare {@param left} to {@param right}
     */
    public static  int compare(L left, ValueAccessor leftAccessor, R right, ValueAccessor rightAccessor)
    {
        return leftAccessor.compare(left, right, rightAccessor);
    }

    public static  boolean equals(L left, ValueAccessor leftAccessor, R right, ValueAccessor rightAccessor)
    {
        return compare(left, leftAccessor, right, rightAccessor) == 0;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy