/** * 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.io.sstable.bitidx; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import org.apache.cassandra.config.ColumnDefinition; import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.io.sstable.Component; import org.apache.cassandra.io.sstable.Descriptor; import org.apache.cassandra.utils.FBUtilities; import org.apache.cassandra.utils.obs.OpenBitSet; import org.apache.cassandra.utils.Pair; public class BitmapIndex { // file metadata is embedded as a serialized object using Avro's metadata system final static String META_KEY = "index_metadata"; // TODO: choose less arbitrary value public final static int MAX_BINS = 32; /** The target number of bits in a data segment, and a rounded max size in bytes. */ final static int SEGMENT_SIZE_BITS = 32000; final static int SEGMENT_SIZE_BYTES = 1 + (SEGMENT_SIZE_BITS / 8); // threadlocal singleton for looking up values in bins final ThreadLocal<Binnable> BINNABLE_SINGLETON = new ThreadLocal<Binnable>() { @Override public Binnable initialValue() { return new Binnable(null); } }; /*************************************************************************/ public final ColumnDefinition cdef; public final Descriptor desc; public final Component component; protected final BinComparator comparator; protected final ArrayList<Binnable> bins; protected BitmapIndex(Descriptor desc, Component component, ColumnDefinition cdef) { this.desc = desc; this.component = component; this.cdef = cdef; this.comparator = new BinComparator(cdef.validator); this.bins = new ArrayList<Binnable>(BitmapIndex.MAX_BINS); } public ByteBuffer name() { return cdef.name; } protected int floor(ByteBuffer v) { int idx = Collections.binarySearch(bins, binnable(v), comparator); if (idx < 0) // round down to previous bin (or -1) return -(2 + idx); // exact match return idx; } /** * An int representing the relative position of the given value to the given bin number. * Results >= 0 indicate that the value is contained by the bin. * @return -2 if (v < min), -1 if (v > max), 0 if (v == min), 1 if (min < v < max), 2 if (v == max). */ protected final int match(int binidx, ByteBuffer v) { Binnable bin = bins.get(binidx); int c = cdef.validator.compare(bin.min, v); if (c > 0) // less than min return -2; if (c == 0) // exact match for min return 0; // else, v > min if (bin.max.remaining() == 0) // greater than single valued bin return -1; // else, is ranged bin c = cdef.validator.compare(v, bin.max); if (c < 0) // falls into ranged bin return 1; if (c == 0) // exact match for max return 2; // else, v > max return -1; } private final Binnable binnable(ByteBuffer value) { Binnable singleton = BINNABLE_SINGLETON.get(); singleton.min = value; return singleton; } @Override public String toString() { StringBuilder buff = new StringBuilder(); buff.append("#<").append(this.getClass().getSimpleName()); buff.append(" [").append(cdef.getIndexName()).append(']'); buff.append(" on ").append(desc.filenameFor(component)); return buff.append('>').toString(); } /** * Comparable superclass for bin lookup. */ static class Binnable { public ByteBuffer min; public ByteBuffer max; public Binnable(ByteBuffer min) { this(min, FBUtilities.EMPTY_BYTE_BUFFER); } public Binnable(ByteBuffer min, ByteBuffer max) { this.min = min; this.max = max; } public String toString(AbstractType type) { StringBuilder buff = new StringBuilder(); buff.append("#<Bin ").append(type.getString(min)).append(','); return buff.append(type.getString(max)).append('>').toString(); } } /** * Bins are only compared using their min value, so a set of bins must not intersect. */ static final class BinComparator implements java.util.Comparator<Binnable> { public final AbstractType type; public BinComparator(AbstractType type) { this.type = type; } @Override public int compare(Binnable o1, Binnable o2) { return type.compare(o1.min, o2.min); } } }