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