|
26 | 26 | import com.google.common.base.Joiner; |
27 | 27 | import com.google.common.collect.ImmutableList; |
28 | 28 |
|
| 29 | +import org.apache.cassandra.io.sstable.ClusteringDescriptor; |
| 30 | +import org.apache.cassandra.db.marshal.AbstractType; |
| 31 | +import org.apache.cassandra.db.marshal.ByteBufferAccessor; |
29 | 32 | import org.apache.cassandra.db.marshal.ValueAccessor; |
30 | 33 | import org.apache.cassandra.db.rows.Row; |
31 | | -import org.apache.cassandra.db.marshal.AbstractType; |
32 | | -import org.apache.cassandra.serializers.MarshalException; |
33 | | - |
34 | 34 | import org.apache.cassandra.io.sstable.IndexInfo; |
| 35 | +import org.apache.cassandra.serializers.MarshalException; |
| 36 | +import org.apache.cassandra.utils.ByteBufferUtil; |
35 | 37 | import org.apache.cassandra.utils.bytecomparable.ByteComparable; |
36 | 38 | import org.apache.cassandra.utils.bytecomparable.ByteSource; |
| 39 | +import org.apache.cassandra.utils.vint.VIntCoding; |
37 | 40 |
|
38 | 41 | import static org.apache.cassandra.utils.bytecomparable.ByteSource.EXCLUDED; |
39 | 42 | import static org.apache.cassandra.utils.bytecomparable.ByteSource.NEXT_COMPONENT; |
@@ -156,6 +159,107 @@ public <V1, V2> int compare(ClusteringPrefix<V1> c1, ClusteringPrefix<V2> c2) |
156 | 159 | return s1 < s2 ? c1.kind().comparedToClustering : -c2.kind().comparedToClustering; |
157 | 160 | } |
158 | 161 |
|
| 162 | + public static int compare(ClusteringDescriptor c1, ClusteringDescriptor c2) |
| 163 | + { |
| 164 | + final int c1Size = c1.clusteringColumnsBound(); |
| 165 | + final int c2Size = c2.clusteringColumnsBound(); |
| 166 | + final int minColumns = Math.min(c1Size, c2Size); |
| 167 | + |
| 168 | + final int cmp = compare(c1.clusteringTypes(), c1.clusteringBuffer(), c2.clusteringBuffer(), minColumns); |
| 169 | + if (cmp != 0) |
| 170 | + return cmp; |
| 171 | + |
| 172 | + final ClusteringPrefix.Kind c1Kind = c1.clusteringKind(); |
| 173 | + final ClusteringPrefix.Kind c2Kind = c2.clusteringKind(); |
| 174 | + if (c1Size == c2Size) |
| 175 | + { |
| 176 | + return ClusteringPrefix.Kind.compare(c1Kind, c2Kind); |
| 177 | + } |
| 178 | + |
| 179 | + return c1Size < c2Size ? c1Kind.comparedToClustering : -c2Kind.comparedToClustering; |
| 180 | + } |
| 181 | + |
| 182 | + public static int compare(AbstractType<?>[] types, ByteBuffer c1, ByteBuffer c2) { |
| 183 | + return compare(types, c1, c2, types.length); |
| 184 | + } |
| 185 | + |
| 186 | + private static int compare(AbstractType<?>[] types, ByteBuffer c1, ByteBuffer c2, int size) |
| 187 | + { |
| 188 | + long clusteringBlock1 = 0; |
| 189 | + long clusteringBlock2 = 0; |
| 190 | + final int position1 = c1.position(); |
| 191 | + final int position2 = c2.position(); |
| 192 | + final int limit1 = c1.limit(); |
| 193 | + final int limit2 = c2.limit(); |
| 194 | + try |
| 195 | + { |
| 196 | + for (int clusteringIndex = 0; clusteringIndex < size; clusteringIndex++) |
| 197 | + { |
| 198 | + if (clusteringIndex % 32 == 0) |
| 199 | + { |
| 200 | + clusteringBlock1 = VIntCoding.readUnsignedVInt(c1); |
| 201 | + clusteringBlock2 = VIntCoding.readUnsignedVInt(c2); |
| 202 | + } |
| 203 | + |
| 204 | + AbstractType<?> type = types[clusteringIndex]; |
| 205 | + |
| 206 | + byte v1Flags = (byte) (clusteringBlock1 & 0b11); |
| 207 | + byte v2Flags = (byte) (clusteringBlock2 & 0b11); |
| 208 | + |
| 209 | + // both values are present |
| 210 | + if ((v1Flags|v2Flags) == 0) |
| 211 | + { |
| 212 | + boolean isByteOrderComparable = type.isByteOrderComparable; |
| 213 | + int vlen1,vlen2; |
| 214 | + if (type.isValueLengthFixed()) |
| 215 | + { |
| 216 | + vlen1 = vlen2 = type.valueLengthIfFixed(); |
| 217 | + } |
| 218 | + else |
| 219 | + { |
| 220 | + vlen1 = VIntCoding.readUnsignedVInt32(c1); |
| 221 | + vlen2 = VIntCoding.readUnsignedVInt32(c2); |
| 222 | + } |
| 223 | + int v1Limit = c1.position() + vlen1; |
| 224 | + if (v1Limit > limit1) |
| 225 | + throw new IllegalArgumentException("Value limit exceeds buffer limit."); |
| 226 | + c1.limit(v1Limit); |
| 227 | + int v2Limit = c2.position() + vlen2; |
| 228 | + if (v2Limit > limit2) |
| 229 | + throw new IllegalArgumentException("Value limit exceeds buffer limit."); |
| 230 | + c2.limit(v2Limit); |
| 231 | + int cmp = isByteOrderComparable ? |
| 232 | + ByteBufferUtil.compareUnsigned(c1, c2) : |
| 233 | + type.compareCustom(c1, ByteBufferAccessor.instance, c2, ByteBufferAccessor.instance); |
| 234 | + if (cmp != 0) |
| 235 | + return cmp; |
| 236 | + c1.position(v1Limit); |
| 237 | + c2.position(v2Limit); |
| 238 | + c1.limit(limit1); |
| 239 | + c2.limit(limit2); |
| 240 | + } |
| 241 | + // present > not present |
| 242 | + else |
| 243 | + { |
| 244 | + // null (0b10) is smaller than empty (0b01) which is smaller than valued (0b00); |
| 245 | + // compare swapped arguments to reverse the order |
| 246 | + int cmp = Long.compare(v2Flags, v1Flags); |
| 247 | + if (cmp != 0) |
| 248 | + return cmp; |
| 249 | + // null/empty == null/empty, continue... |
| 250 | + } |
| 251 | + clusteringBlock1 = clusteringBlock1 >>> 2; |
| 252 | + clusteringBlock2 = clusteringBlock2 >>> 2; |
| 253 | + } |
| 254 | + } |
| 255 | + finally |
| 256 | + { |
| 257 | + c1.position(position1).limit(limit1); |
| 258 | + c2.position(position2).limit(limit2); |
| 259 | + } |
| 260 | + return 0; |
| 261 | + } |
| 262 | + |
159 | 263 | public <V1, V2> int compare(Clustering<V1> c1, Clustering<V2> c2) |
160 | 264 | { |
161 | 265 | return compare(c1, c2, size()); |
|
0 commit comments