blob: 6df425c0b32b9f50467df2b06d32ae86e723b1c3 [file] [log] [blame]
/*
* 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.utils.bytecomparable;
import java.nio.ByteBuffer;
/**
* Interface indicating a value can be represented/identified by a comparable {@link ByteSource}.
*
* All Cassandra types that can be used as part of a primary key have a corresponding byte-comparable translation,
* detailed in ByteComparable.md. Byte-comparable representations are used in some memtable as well as primary and
* secondary index implementations.
*/
public interface ByteComparable
{
/**
* Returns a source that generates the byte-comparable representation of the value byte by byte.
*/
ByteSource asComparableBytes(Version version);
enum Version
{
LEGACY, // Encoding used in legacy sstable format; forward (value to byte-comparable) translation only
OSS50, // CASSANDRA 5.0 encoding
}
ByteComparable EMPTY = (Version version) -> ByteSource.EMPTY;
/**
* Construct a human-readable string from the byte-comparable representation. Used for debugging.
*/
default String byteComparableAsString(Version version)
{
StringBuilder builder = new StringBuilder();
ByteSource stream = asComparableBytes(version);
if (stream == null)
return "null";
for (int b = stream.next(); b != ByteSource.END_OF_STREAM; b = stream.next())
builder.append(Integer.toHexString((b >> 4) & 0xF)).append(Integer.toHexString(b & 0xF));
return builder.toString();
}
// Simple factories used for testing
static ByteComparable of(String s)
{
return v -> ByteSource.of(s, v);
}
static ByteComparable of(long value)
{
return v -> ByteSource.of(value);
}
static ByteComparable of(int value)
{
return v -> ByteSource.of(value);
}
static ByteComparable fixedLength(ByteBuffer bytes)
{
return v -> ByteSource.fixedLength(bytes);
}
static ByteComparable fixedLength(byte[] bytes)
{
return v -> ByteSource.fixedLength(bytes);
}
/**
* Returns a separator for two byte sources, i.e. something that is definitely > prevMax, and <= currMin, assuming
* prevMax < currMin.
* This returns the shortest prefix of currMin that is greater than prevMax.
*/
static ByteComparable separatorPrefix(ByteComparable prevMax, ByteComparable currMin)
{
return version -> ByteSource.separatorPrefix(prevMax.asComparableBytes(version), currMin.asComparableBytes(version));
}
/**
* Returns a separator for two byte comparable, i.e. something that is definitely > prevMax, and <= currMin, assuming
* prevMax < currMin.
* This is a stream of length 1 longer than the common prefix of the two streams, with last byte one higher than the
* prevMax stream.
*/
static ByteComparable separatorGt(ByteComparable prevMax, ByteComparable currMin)
{
return version -> ByteSource.separatorGt(prevMax.asComparableBytes(version), currMin.asComparableBytes(version));
}
static ByteComparable cut(ByteComparable src, int cutoff)
{
return version -> ByteSource.cut(src.asComparableBytes(version), cutoff);
}
/**
* Return the length of a byte comparable, not including the terminator byte.
*/
static int length(ByteComparable src, Version version)
{
int l = 0;
ByteSource s = src.asComparableBytes(version);
while (s.next() != ByteSource.END_OF_STREAM)
++l;
return l;
}
/**
* Compare two byte-comparable values by their byte-comparable representation. Used for tests.
*
* @return the result of the lexicographic unsigned byte comparison of the byte-comparable representations of the
* two arguments
*/
static int compare(ByteComparable bytes1, ByteComparable bytes2, Version version)
{
ByteSource s1 = bytes1.asComparableBytes(version);
ByteSource s2 = bytes2.asComparableBytes(version);
if (s1 == null || s2 == null)
return Boolean.compare(s1 != null, s2 != null);
while (true)
{
int b1 = s1.next();
int b2 = s2.next();
int cmp = Integer.compare(b1, b2);
if (cmp != 0)
return cmp;
if (b1 == ByteSource.END_OF_STREAM)
return 0;
}
}
/**
* Returns the length of the minimum prefix that differentiates the two given byte-comparable representations.
*/
static int diffPoint(ByteComparable bytes1, ByteComparable bytes2, Version version)
{
ByteSource s1 = bytes1.asComparableBytes(version);
ByteSource s2 = bytes2.asComparableBytes(version);
int pos = 1;
int b;
while ((b = s1.next()) == s2.next() && b != ByteSource.END_OF_STREAM)
++pos;
return pos;
}
}