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, Version 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 KIND, 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 java.io.IOException; 022import java.util.Iterator; 023import java.util.SortedSet; 024 025import org.apache.commons.lang3.NotImplementedException; 026import org.apache.hadoop.fs.Path; 027import org.apache.hadoop.hbase.Cell; 028import org.apache.hadoop.hbase.PrivateCellUtil; 029import org.apache.yetus.audience.InterfaceAudience; 030import org.apache.hadoop.hbase.client.Scan; 031 032/** 033 * A scanner of a single memstore segment. 034 */ 035@InterfaceAudience.Private 036public class SegmentScanner implements KeyValueScanner { 037 038 /** 039 * Order of this scanner relative to other scanners. See 040 * {@link KeyValueScanner#getScannerOrder()}. 041 */ 042 private long scannerOrder; 043 private static final long DEFAULT_SCANNER_ORDER = Long.MAX_VALUE; 044 045 // the observed structure 046 protected final Segment segment; 047 // the highest relevant MVCC 048 private long readPoint; 049 // the current iterator that can be reinitialized by 050 // seek(), backwardSeek(), or reseek() 051 protected Iterator<Cell> iter; 052 // the pre-calculated cell to be returned by peek() 053 protected Cell current = null; 054 // or next() 055 // A flag represents whether could stop skipping KeyValues for MVCC 056 // if have encountered the next row. Only used for reversed scan 057 private boolean stopSkippingKVsIfNextRow = false; 058 // Stop skipping KeyValues for MVCC if finish this row. Only used for reversed scan 059 private Cell stopSkippingKVsRow; 060 // last iterated KVs by seek (to restore the iterator state after reseek) 061 private Cell last = null; 062 063 // flag to indicate if this scanner is closed 064 protected boolean closed = false; 065 066 protected SegmentScanner(Segment segment, long readPoint) { 067 this(segment, readPoint, DEFAULT_SCANNER_ORDER); 068 } 069 070 /** 071 * @param scannerOrder see {@link KeyValueScanner#getScannerOrder()}. 072 * Scanners are ordered from 0 (oldest) to newest in increasing order. 073 */ 074 protected SegmentScanner(Segment segment, long readPoint, long scannerOrder) { 075 this.segment = segment; 076 this.readPoint = readPoint; 077 //increase the reference count so the underlying structure will not be de-allocated 078 this.segment.incScannerCount(); 079 iter = segment.iterator(); 080 // the initialization of the current is required for working with heap of SegmentScanners 081 updateCurrent(); 082 this.scannerOrder = scannerOrder; 083 if (current == null) { 084 // nothing to fetch from this scanner 085 close(); 086 } 087 } 088 089 /** 090 * Look at the next Cell in this scanner, but do not iterate the scanner 091 * @return the currently observed Cell 092 */ 093 @Override 094 public Cell peek() { // sanity check, the current should be always valid 095 if (closed) { 096 return null; 097 } 098 if (current!=null && current.getSequenceId() > readPoint) { 099 throw new RuntimeException("current is invalid: read point is "+readPoint+", " + 100 "while current sequence id is " +current.getSequenceId()); 101 } 102 return current; 103 } 104 105 /** 106 * Return the next Cell in this scanner, iterating the scanner 107 * @return the next Cell or null if end of scanner 108 */ 109 @Override 110 public Cell next() throws IOException { 111 if (closed) { 112 return null; 113 } 114 Cell oldCurrent = current; 115 updateCurrent(); // update the currently observed Cell 116 return oldCurrent; 117 } 118 119 /** 120 * Seek the scanner at or after the specified Cell. 121 * @param cell seek value 122 * @return true if scanner has values left, false if end of scanner 123 */ 124 @Override 125 public boolean seek(Cell cell) throws IOException { 126 if (closed) { 127 return false; 128 } 129 if(cell == null) { 130 close(); 131 return false; 132 } 133 // restart the iterator from new key 134 iter = getIterator(cell); 135 // last is going to be reinitialized in the next getNext() call 136 last = null; 137 updateCurrent(); 138 return (current != null); 139 } 140 141 protected Iterator<Cell> getIterator(Cell cell) { 142 return segment.tailSet(cell).iterator(); 143 } 144 145 /** 146 * Reseek the scanner at or after the specified KeyValue. 147 * This method is guaranteed to seek at or after the required key only if the 148 * key comes after the current position of the scanner. Should not be used 149 * to seek to a key which may come before the current position. 150 * 151 * @param cell seek value (should be non-null) 152 * @return true if scanner has values left, false if end of scanner 153 */ 154 @Override 155 public boolean reseek(Cell cell) throws IOException { 156 if (closed) { 157 return false; 158 } 159 /* 160 See HBASE-4195 & HBASE-3855 & HBASE-6591 for the background on this implementation. 161 This code is executed concurrently with flush and puts, without locks. 162 The ideal implementation for performance would use the sub skip list implicitly 163 pointed by the iterator. Unfortunately the Java API does not offer a method to 164 get it. So we remember the last keys we iterated to and restore 165 the reseeked set to at least that point. 166 */ 167 iter = getIterator(getHighest(cell, last)); 168 updateCurrent(); 169 return (current != null); 170 } 171 172 /** 173 * Seek the scanner at or before the row of specified Cell, it firstly 174 * tries to seek the scanner at or after the specified Cell, return if 175 * peek KeyValue of scanner has the same row with specified Cell, 176 * otherwise seek the scanner at the first Cell of the row which is the 177 * previous row of specified KeyValue 178 * 179 * @param key seek Cell 180 * @return true if the scanner is at the valid KeyValue, false if such Cell does not exist 181 */ 182 @Override 183 public boolean backwardSeek(Cell key) throws IOException { 184 if (closed) { 185 return false; 186 } 187 seek(key); // seek forward then go backward 188 if (peek() == null || segment.compareRows(peek(), key) > 0) { 189 return seekToPreviousRow(key); 190 } 191 return true; 192 } 193 194 /** 195 * Seek the scanner at the first Cell of the row which is the previous row 196 * of specified key 197 * 198 * @param cell seek value 199 * @return true if the scanner at the first valid Cell of previous row, 200 * false if not existing such Cell 201 */ 202 @Override 203 public boolean seekToPreviousRow(Cell cell) throws IOException { 204 if (closed) { 205 return false; 206 } 207 boolean keepSeeking; 208 Cell key = cell; 209 do { 210 Cell firstKeyOnRow = PrivateCellUtil.createFirstOnRow(key); 211 SortedSet<Cell> cellHead = segment.headSet(firstKeyOnRow); 212 Cell lastCellBeforeRow = cellHead.isEmpty() ? null : cellHead.last(); 213 if (lastCellBeforeRow == null) { 214 current = null; 215 return false; 216 } 217 Cell firstKeyOnPreviousRow = PrivateCellUtil.createFirstOnRow(lastCellBeforeRow); 218 this.stopSkippingKVsIfNextRow = true; 219 this.stopSkippingKVsRow = firstKeyOnPreviousRow; 220 seek(firstKeyOnPreviousRow); 221 this.stopSkippingKVsIfNextRow = false; 222 if (peek() == null 223 || segment.getComparator().compareRows(peek(), firstKeyOnPreviousRow) > 0) { 224 keepSeeking = true; 225 key = firstKeyOnPreviousRow; 226 continue; 227 } else { 228 keepSeeking = false; 229 } 230 } while (keepSeeking); 231 return true; 232 } 233 234 /** 235 * Seek the scanner at the first KeyValue of last row 236 * 237 * @return true if scanner has values left, false if the underlying data is empty 238 */ 239 @Override 240 public boolean seekToLastRow() throws IOException { 241 if (closed) { 242 return false; 243 } 244 Cell higherCell = segment.isEmpty() ? null : segment.last(); 245 if (higherCell == null) { 246 return false; 247 } 248 249 Cell firstCellOnLastRow = PrivateCellUtil.createFirstOnRow(higherCell); 250 251 if (seek(firstCellOnLastRow)) { 252 return true; 253 } else { 254 return seekToPreviousRow(higherCell); 255 } 256 } 257 258 /** 259 * @see KeyValueScanner#getScannerOrder() 260 */ 261 @Override 262 public long getScannerOrder() { 263 return scannerOrder; 264 } 265 266 /** 267 * Close the KeyValue scanner. 268 */ 269 @Override 270 public void close() { 271 if (closed) { 272 return; 273 } 274 getSegment().decScannerCount(); 275 closed = true; 276 } 277 278 /** 279 * This functionality should be resolved in the higher level which is 280 * MemStoreScanner, currently returns true as default. Doesn't throw 281 * IllegalStateException in order not to change the signature of the 282 * overridden method 283 */ 284 @Override 285 public boolean shouldUseScanner(Scan scan, HStore store, long oldestUnexpiredTS) { 286 return getSegment().shouldSeek(scan.getColumnFamilyTimeRange() 287 .getOrDefault(store.getColumnFamilyDescriptor().getName(), scan.getTimeRange()), oldestUnexpiredTS); 288 } 289 290 @Override 291 public boolean requestSeek(Cell c, boolean forward, boolean useBloom) 292 throws IOException { 293 return NonLazyKeyValueScanner.doRealSeek(this, c, forward); 294 } 295 296 /** 297 * This scanner is working solely on the in-memory MemStore and doesn't work on 298 * store files, MutableCellSetSegmentScanner always does the seek, 299 * therefore always returning true. 300 */ 301 @Override 302 public boolean realSeekDone() { 303 return true; 304 } 305 306 /** 307 * This function should be never called on scanners that always do real seek operations (i.e. most 308 * of the scanners and also this one). The easiest way to achieve this is to call 309 * {@link #realSeekDone()} first. 310 */ 311 @Override 312 public void enforceSeek() throws IOException { 313 throw new NotImplementedException("enforceSeek cannot be called on a SegmentScanner"); 314 } 315 316 /** 317 * @return true if this is a file scanner. Otherwise a memory scanner is assumed. 318 */ 319 @Override 320 public boolean isFileScanner() { 321 return false; 322 } 323 324 @Override 325 public Path getFilePath() { 326 return null; 327 } 328 329 /** 330 * @return the next key in the index (the key to seek to the next block) 331 * if known, or null otherwise 332 * Not relevant for in-memory scanner 333 */ 334 @Override 335 public Cell getNextIndexedKey() { 336 return null; 337 } 338 339 /** 340 * Called after a batch of rows scanned (RPC) and set to be returned to client. Any in between 341 * cleanup can be done here. Nothing to be done for MutableCellSetSegmentScanner. 342 */ 343 @Override 344 public void shipped() throws IOException { 345 // do nothing 346 } 347 348 //debug method 349 @Override 350 public String toString() { 351 String res = "Store segment scanner of type "+this.getClass().getName()+"; "; 352 res += "Scanner order " + getScannerOrder() + "; "; 353 res += getSegment().toString(); 354 return res; 355 } 356 357 /********************* Private Methods **********************/ 358 359 private Segment getSegment(){ 360 return segment; 361 } 362 363 /** 364 * Private internal method for iterating over the segment, 365 * skipping the cells with irrelevant MVCC 366 */ 367 protected void updateCurrent() { 368 Cell next = null; 369 370 try { 371 while (iter.hasNext()) { 372 next = iter.next(); 373 if (next.getSequenceId() <= this.readPoint) { 374 current = next; 375 return;// skip irrelevant versions 376 } 377 // for backwardSeek() stay in the boundaries of a single row 378 if (stopSkippingKVsIfNextRow && 379 segment.compareRows(next, stopSkippingKVsRow) > 0) { 380 current = null; 381 return; 382 } 383 } // end of while 384 385 current = null; // nothing found 386 } finally { 387 if (next != null) { 388 // in all cases, remember the last KV we iterated to, needed for reseek() 389 last = next; 390 } 391 } 392 } 393 394 /** 395 * Private internal method that returns the higher of the two key values, or null 396 * if they are both null 397 */ 398 private Cell getHighest(Cell first, Cell second) { 399 if (first == null && second == null) { 400 return null; 401 } 402 if (first != null && second != null) { 403 int compare = segment.compare(first, second); 404 return (compare > 0 ? first : second); 405 } 406 return (first != null ? first : second); 407 } 408}