001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.regionserver; 019 020import java.util.Collection; 021import java.util.Comparator; 022import java.util.Iterator; 023import java.util.Map; 024import java.util.NavigableMap; 025import java.util.NavigableSet; 026import java.util.Set; 027import org.apache.hadoop.hbase.Cell; 028import org.apache.yetus.audience.InterfaceAudience; 029 030/** 031 * CellFlatMap stores a constant number of elements and is immutable after creation stage. Being 032 * immutable, the CellFlatMap can be implemented as array. The actual array can be on- or off-heap 033 * and is implemented in concrete class derived from CellFlatMap. The CellFlatMap uses no 034 * synchronization primitives, it is assumed to be created by a single thread and then it can be 035 * read-only by multiple threads. The "flat" in the name, means that the memory layout of the Map is 036 * sequential array and thus requires less memory than ConcurrentSkipListMap. 037 */ 038@InterfaceAudience.Private 039public abstract class CellFlatMap<T extends Cell> implements NavigableMap<T, T> { 040 041 private final Comparator<? super T> comparator; 042 protected int minCellIdx = 0; // the index of the minimal cell (for sub-sets) 043 protected int maxCellIdx = 0; // the index of the cell after the maximal cell (for sub-sets) 044 private boolean descending = false; 045 046 /* C-tor */ 047 public CellFlatMap(Comparator<? super T> comparator, int min, int max, boolean d) { 048 this.comparator = comparator; 049 this.minCellIdx = min; 050 this.maxCellIdx = max; 051 this.descending = d; 052 } 053 054 /* Used for abstract CellFlatMap creation, implemented by derived class */ 055 protected abstract CellFlatMap<T> createSubCellFlatMap(int min, int max, boolean descending); 056 057 /* Returns the i-th cell in the cell block */ 058 protected abstract T getCell(int i); 059 060 /** 061 * Binary search for a given key in between given boundaries of the array. Positive returned 062 * numbers mean the index. Negative returned numbers means the key not found. The absolute value 063 * of the output is the possible insert index for the searched key In twos-complement, (-1 * 064 * insertion point)-1 is the bitwise not of the insert point. 065 * @param needle The key to look for in all of the entries 066 * @return Same return value as Arrays.binarySearch. 067 */ 068 private int find(T needle) { 069 int begin = minCellIdx; 070 int end = maxCellIdx - 1; 071 072 while (begin <= end) { 073 int mid = begin + ((end - begin) >> 1); 074 T midCell = getCell(mid); 075 int compareRes = comparator.compare(midCell, needle); 076 077 if (compareRes == 0) { 078 return mid; // 0 means equals. We found the key 079 } 080 // Key not found. Check the comparison results; reverse the meaning of 081 // the comparison in case the order is descending (using XOR) 082 if ((compareRes < 0) ^ descending) { 083 // midCell is less than needle so we need to look at farther up 084 begin = mid + 1; 085 } else { 086 // midCell is greater than needle so we need to look down 087 end = mid - 1; 088 } 089 } 090 091 return (-1 * begin) - 1; 092 } 093 094 /** 095 * Get the index of the given anchor key for creating subsequent set. It doesn't matter whether 096 * the given key exists in the set or not. taking into consideration whether the key should be 097 * inclusive or exclusive. 098 */ 099 private int getValidIndex(T key, boolean inclusive, boolean tail) { 100 final int index = find(key); 101 // get the valid (positive) insertion point from the output of the find() method 102 int insertionPoint = index < 0 ? ~index : index; 103 104 // correct the insertion point in case the given anchor key DOES EXIST in the set 105 if (index >= 0) { 106 if (descending && !(tail ^ inclusive)) { 107 // for the descending case 108 // if anchor for head set (tail=false) AND anchor is not inclusive -> move the insertion pt 109 // if anchor for tail set (tail=true) AND the keys is inclusive -> move the insertion point 110 // because the end index of a set is the index of the cell after the maximal cell 111 insertionPoint += 1; 112 } else if (!descending && (tail ^ inclusive)) { 113 // for the ascending case 114 // if anchor for head set (tail=false) AND anchor is inclusive -> move the insertion point 115 // because the end index of a set is the index of the cell after the maximal cell 116 // if anchor for tail set (tail=true) AND the keys is not inclusive -> move the insertion pt 117 insertionPoint += 1; 118 } 119 } 120 // insert the insertion point into the valid range, 121 // as we may enlarge it too much in the above correction 122 return Math.min(Math.max(insertionPoint, minCellIdx), maxCellIdx); 123 } 124 125 @Override 126 public Comparator<? super T> comparator() { 127 return comparator; 128 } 129 130 @Override 131 public int size() { 132 return maxCellIdx - minCellIdx; 133 } 134 135 @Override 136 public boolean isEmpty() { 137 return (size() == 0); 138 } 139 140 // ---------------- Sub-Maps ---------------- 141 @Override 142 public NavigableMap<T, T> subMap(T fromKey, boolean fromInclusive, T toKey, boolean toInclusive) { 143 final int lessCellIndex = getValidIndex(fromKey, fromInclusive, true); 144 final int greaterCellIndex = getValidIndex(toKey, toInclusive, false); 145 if (descending) { 146 return createSubCellFlatMap(greaterCellIndex, lessCellIndex, descending); 147 } else { 148 return createSubCellFlatMap(lessCellIndex, greaterCellIndex, descending); 149 } 150 } 151 152 @Override 153 public NavigableMap<T, T> headMap(T toKey, boolean inclusive) { 154 if (descending) { 155 return createSubCellFlatMap(getValidIndex(toKey, inclusive, false), maxCellIdx, descending); 156 } else { 157 return createSubCellFlatMap(minCellIdx, getValidIndex(toKey, inclusive, false), descending); 158 } 159 } 160 161 @Override 162 public NavigableMap<T, T> tailMap(T fromKey, boolean inclusive) { 163 if (descending) { 164 return createSubCellFlatMap(minCellIdx, getValidIndex(fromKey, inclusive, true), descending); 165 } else { 166 return createSubCellFlatMap(getValidIndex(fromKey, inclusive, true), maxCellIdx, descending); 167 } 168 } 169 170 @Override 171 public NavigableMap<T, T> descendingMap() { 172 return createSubCellFlatMap(minCellIdx, maxCellIdx, true); 173 } 174 175 @Override 176 public NavigableMap<T, T> subMap(T k1, T k2) { 177 return this.subMap(k1, true, k2, true); 178 } 179 180 @Override 181 public NavigableMap<T, T> headMap(T k) { 182 return this.headMap(k, true); 183 } 184 185 @Override 186 public NavigableMap<T, T> tailMap(T k) { 187 return this.tailMap(k, true); 188 } 189 190 // -------------------------------- Key's getters -------------------------------- 191 @Override 192 public T firstKey() { 193 if (isEmpty()) { 194 return null; 195 } 196 return descending ? getCell(maxCellIdx - 1) : getCell(minCellIdx); 197 } 198 199 @Override 200 public T lastKey() { 201 if (isEmpty()) { 202 return null; 203 } 204 return descending ? getCell(minCellIdx) : getCell(maxCellIdx - 1); 205 } 206 207 @Override 208 public T lowerKey(T k) { 209 if (isEmpty()) { 210 return null; 211 } 212 int index = find(k); 213 // If index>=0 there's a key exactly equal 214 index = (index >= 0) ? index - 1 : -(index); 215 return (index < minCellIdx || index >= maxCellIdx) ? null : getCell(index); 216 } 217 218 @Override 219 public T floorKey(T k) { 220 if (isEmpty()) { 221 return null; 222 } 223 int index = find(k); 224 index = (index >= 0) ? index : -(index); 225 return (index < minCellIdx || index >= maxCellIdx) ? null : getCell(index); 226 } 227 228 @Override 229 public T ceilingKey(T k) { 230 if (isEmpty()) { 231 return null; 232 } 233 int index = find(k); 234 index = (index >= 0) ? index : -(index) + 1; 235 return (index < minCellIdx || index >= maxCellIdx) ? null : getCell(index); 236 } 237 238 @Override 239 public T higherKey(T k) { 240 if (isEmpty()) { 241 return null; 242 } 243 int index = find(k); 244 index = (index >= 0) ? index + 1 : -(index) + 1; 245 return (index < minCellIdx || index >= maxCellIdx) ? null : getCell(index); 246 } 247 248 @Override 249 public boolean containsKey(Object o) { 250 int index = find((T) o); 251 return (index >= 0); 252 } 253 254 @Override 255 public boolean containsValue(Object o) { // use containsKey(Object o) instead 256 throw new UnsupportedOperationException("Use containsKey(Object o) instead"); 257 } 258 259 @Override 260 public T get(Object o) { 261 int index = find((T) o); 262 return (index >= 0) ? getCell(index) : null; 263 } 264 265 // -------------------------------- Entry's getters -------------------------------- 266 267 private static class CellFlatMapEntry<T> implements Entry<T, T> { 268 private final T cell; 269 270 public CellFlatMapEntry(T cell) { 271 this.cell = cell; 272 } 273 274 @Override 275 public T getKey() { 276 return cell; 277 } 278 279 @Override 280 public T getValue() { 281 return cell; 282 } 283 284 @Override 285 public T setValue(T value) { 286 throw new UnsupportedOperationException(); 287 } 288 } 289 290 @Override 291 public Entry<T, T> lowerEntry(T k) { 292 T cell = lowerKey(k); 293 if (cell == null) { 294 return null; 295 } 296 return new CellFlatMapEntry<>(cell); 297 } 298 299 @Override 300 public Entry<T, T> higherEntry(T k) { 301 T cell = higherKey(k); 302 if (cell == null) { 303 return null; 304 } 305 return new CellFlatMapEntry<>(cell); 306 } 307 308 @Override 309 public Entry<T, T> ceilingEntry(T k) { 310 T cell = ceilingKey(k); 311 if (cell == null) { 312 return null; 313 } 314 return new CellFlatMapEntry<>(cell); 315 } 316 317 @Override 318 public Entry<T, T> floorEntry(T k) { 319 T cell = floorKey(k); 320 if (cell == null) { 321 return null; 322 } 323 return new CellFlatMapEntry<>(cell); 324 } 325 326 @Override 327 public Entry<T, T> firstEntry() { 328 T cell = firstKey(); 329 if (cell == null) { 330 return null; 331 } 332 return new CellFlatMapEntry<>(cell); 333 } 334 335 @Override 336 public Entry<T, T> lastEntry() { 337 T cell = lastKey(); 338 if (cell == null) { 339 return null; 340 } 341 return new CellFlatMapEntry<>(cell); 342 } 343 344 // The following 2 methods (pollFirstEntry, pollLastEntry) are unsupported because these are 345 // updating methods. 346 @Override 347 public Entry<T, T> pollFirstEntry() { 348 throw new UnsupportedOperationException(); 349 } 350 351 @Override 352 public Entry<T, T> pollLastEntry() { 353 throw new UnsupportedOperationException(); 354 } 355 356 // -------------------------------- Updates -------------------------------- 357 // All updating methods below are unsupported. 358 // Assuming an array of Cells will be allocated externally, 359 // fill up with Cells and provided in construction time. 360 // Later the structure is immutable. 361 @Override 362 public T put(T k, T v) { 363 throw new UnsupportedOperationException(); 364 } 365 366 @Override 367 public void clear() { 368 throw new UnsupportedOperationException(); 369 } 370 371 @Override 372 public T remove(Object o) { 373 throw new UnsupportedOperationException(); 374 } 375 376 @Override 377 public void putAll(Map<? extends T, ? extends T> map) { 378 throw new UnsupportedOperationException(); 379 } 380 381 // -------------------------------- Sub-Sets -------------------------------- 382 @Override 383 public NavigableSet<T> navigableKeySet() { 384 throw new UnsupportedOperationException(); 385 } 386 387 @Override 388 public NavigableSet<T> descendingKeySet() { 389 throw new UnsupportedOperationException(); 390 } 391 392 @Override 393 public NavigableSet<T> keySet() { 394 throw new UnsupportedOperationException(); 395 } 396 397 @Override 398 public Collection<T> values() { 399 return new CellFlatMapCollection(); 400 } 401 402 @Override 403 public Set<Entry<T, T>> entrySet() { 404 throw new UnsupportedOperationException(); 405 } 406 407 // -------------------------------- Iterator K -------------------------------- 408 private final class CellFlatMapIterator implements Iterator<T> { 409 int index; 410 411 private CellFlatMapIterator() { 412 index = descending ? maxCellIdx - 1 : minCellIdx; 413 } 414 415 @Override 416 public boolean hasNext() { 417 return descending ? (index >= minCellIdx) : (index < maxCellIdx); 418 } 419 420 @Override 421 public T next() { 422 T result = getCell(index); 423 if (descending) { 424 index--; 425 } else { 426 index++; 427 } 428 return result; 429 } 430 431 @Override 432 public void remove() { 433 throw new UnsupportedOperationException(); 434 } 435 } 436 437 // -------------------------------- Collection -------------------------------- 438 private final class CellFlatMapCollection implements Collection<T> { 439 440 @Override 441 public int size() { 442 return CellFlatMap.this.size(); 443 } 444 445 @Override 446 public boolean isEmpty() { 447 return CellFlatMap.this.isEmpty(); 448 } 449 450 @Override 451 public void clear() { 452 throw new UnsupportedOperationException(); 453 } 454 455 @Override 456 public boolean contains(Object o) { 457 return containsKey(o); 458 } 459 460 @Override 461 public Iterator<T> iterator() { 462 return new CellFlatMapIterator(); 463 } 464 465 @Override 466 public Object[] toArray() { 467 throw new UnsupportedOperationException(); 468 } 469 470 @Override 471 public <T> T[] toArray(T[] ts) { 472 throw new UnsupportedOperationException(); 473 } 474 475 @Override 476 public boolean add(T k) { 477 throw new UnsupportedOperationException(); 478 } 479 480 @Override 481 public boolean remove(Object o) { 482 throw new UnsupportedOperationException(); 483 } 484 485 @Override 486 public boolean containsAll(Collection<?> collection) { 487 throw new UnsupportedOperationException(); 488 } 489 490 @Override 491 public boolean addAll(Collection<? extends T> collection) { 492 throw new UnsupportedOperationException(); 493 } 494 495 @Override 496 public boolean removeAll(Collection<?> collection) { 497 throw new UnsupportedOperationException(); 498 } 499 500 @Override 501 public boolean retainAll(Collection<?> collection) { 502 throw new UnsupportedOperationException(); 503 } 504 } 505}