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}