HBase分析之Get、Scan(二)RegionScanner

来源:互联网 发布:山东软件开发 编辑:程序博客网 时间:2024/06/07 00:00

这篇我们继续看moreRows = scanner.nextRaw(values, scannerContext);,这里的scanner是通过HRegion#getScanner创建出来的一个RegionScannerImpl实例,他的nextRaw方法调用了RegionScannerImpl#nextInternal方法。这个方法主要目的是获取下一条数据放入results,并取得返回值表示是否还有更多的数据。

我们知道HBase没有建立索引,数据的查找是靠遍历文件实现的,所以查找下一行数据需要一个while循环。为了方便理解,代码稍有调整。

private boolean nextInternal(List<Cell> results, ScannerContext scannerContext)    throws IOException {  while (true) {    ...  }}
  1. 剥去while,看内部,首先从storeHeap里取了个值,第一次取得的值是null,后续会往storeHeap里塞数据。前一篇我们说过,多次的请求其实用的是同一个Scanner实例,所以可以在一次请求时,将值放入storeHeap,下一次请求还是可以从storeHeap里取出来。
Cell current = this.storeHeap.peek();byte[] currentRow = null;int offset = 0;short length = 0;if (current != null) {  currentRow = current.getRowArray();  offset = current.getRowOffset();  length = current.getRowLength();}
  1. 判断当前数据是否是停止行,如果是停止行,就直接返回false,表示没有更多数据了。这里就是客户端设置scan.setStopRow可以提高效率的原因,因为直接return了false,所以就不会继续遍历了。
boolean stopRow = isStopRow(currentRow, offset, length);...if (stopRow) {  return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();}
  1. 接着调用过滤器判断下一步的行为,如果这条数据无法满足filter的要求,就再判断下是否还有更多数据,没有就返回,有就continue while循环。Filter曾经被人诟病,即使后续的数据无法满足filter要求了,也必须遍历完,所以这里多出了个isFilterDoneInternal方法,来判断是否退出循环,返回false。
if (filterRowKey(currentRow, offset, length)) {  if (isFilterDoneInternal()) {    return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();  }  boolean moreRows = nextRow(scannerContext, currentRow, offset, length);  if (!moreRows) {    return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();  }  results.clear();  continue;}
  1. 这个时候,stopRow和filterRowKey都放行了,可以读取数据了。
populateResult(results, this.storeHeap, scannerContext, currentRow, offset, length);

这个方法里遍历数据,查找到下一行。populateResult的遍历和外层nextInternal遍历的差别在于,populateResult遍历负责找齐一行数据的所有列,从他while循环的条件moreCellsInRow就能看出来,外层的遍历负责对这一行数据进行过滤,包括stopRow、Filter。其他方法都很简单,就看heap.next(results, scannerContext);方法,这里的heap就是this.storeHeap。

private boolean populateResult(List<Cell> results, KeyValueHeap heap,    ScannerContext scannerContext, byte[] currentRow, int offset, short length)    throws IOException {  Cell nextKv;  ...    do {      heap.next(results, scannerContext);      nextKv = heap.peek();      // 看下一行数据的row是不是和当前行一样      moreCellsInRow = moreCellsInRow(nextKv, currentRow, offset, length);      if (!moreCellsInRow) incrementCountOfRowsScannedMetric(scannerContext);      ...    } while (moreCellsInRow);  ...  return nextKv != null;}

再看heap.next(results, scannerContext);方法,这里调用了current,即StoreScanner来读取下一行数据,StoreScanner.next放到下一篇来说。

@Overridepublic boolean next(List<Cell> result, ScannerContext scannerContext) throws IOException {  ...  InternalScanner currentAsInternal = (InternalScanner)this.current;  boolean moreCells = currentAsInternal.next(result, scannerContext);  ...  return moreCells;}
  1. 取完数据,再看看下一行数据是否是stopRow
Cell nextKv = this.storeHeap.peek();stopRow = nextKv == null ||    isStopRow(nextKv.getRowArray(), nextKv.getRowOffset(), nextKv.getRowLength());
  1. 如果这次没找到数据,且不是停止行,就继续while遍历。
if (results.isEmpty()) {  incrementCountOfRowsFilteredMetric(scannerContext);  boolean moreRows = nextRow(scannerContext, currentRow, offset, length);  if (!moreRows) {    return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();  }  if (!stopRow) continue;}
  1. 最后判断一次stopRow,这样查找就完事了。
if (stopRow) {  return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();} else {  return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();}

下篇继续看HBase分析之StoreScanner

-END-

原创粉丝点击