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}