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