[HBase]Get

来源:互联网 发布:搜达足球数据 编辑:程序博客网 时间:2024/05/18 15:07

转载自:http://iwinit.iteye.com/blog/1831678

Get主要流程:

1.拼装Scanner

2.调用scanner的next方法取记录

3.返回result

 

scanner入口是RegionScanner,代表扫描一个region,其实现RegionScannerImpl有一个属性KeyValueHeap,这个KeyValueHeap又包装了多个StoreScanner。每个StoreScanner对应一个column family,而每个StoreScanner又对应一个MemStoreScanner和多个StoreFileScanner。MemStoreScanner代表对memstore进行scan,StoreFileScanner对应一个storefile。其类图如下

 

0.94里实现如下

HRegion的Get入口

 

Java代码  收藏代码
  1. private List<KeyValue> get(Get get, boolean withCoprocessor)  
  2.   throws IOException {  
  3.     long now = EnvironmentEdgeManager.currentTimeMillis();  
  4.   
  5.     List<KeyValue> results = new ArrayList<KeyValue>();  
  6.   
  7.     .....  
  8.     //转成Scan,startRow和stopRow一样  
  9.     Scan scan = new Scan(get);  
  10.   
  11.     RegionScanner scanner = null;  
  12.     try {  
  13.     //按照上述结构,构造scanner,这里会有seek操作,表示scanner已经做好next准备了  
  14.       scanner = getScanner(scan);  
  15.     //取数据  
  16.       scanner.next(results);  
  17.     } finally {  
  18.       if (scanner != null)  
  19.         scanner.close();  
  20.     }  
  21.     ......  
  22.       
  23.     return results;  
  24.   }  
 RegionScannerImpl构造
Java代码  收藏代码
  1.    RegionScannerImpl(Scan scan, List<KeyValueScanner> additionalScanners) throws IOException {  
  2.   
  3.      this.maxResultSize = scan.getMaxResultSize();  
  4.      this.filter = scan.getFilter();  
  5.      this.batch = scan.getBatch();  
  6.      if (Bytes.equals(scan.getStopRow(), HConstants.EMPTY_END_ROW)) {  
  7.        this.stopRow = null;  
  8.      } else {  
  9.        this.stopRow = scan.getStopRow();  
  10.      }  
  11.      // If we are doing a get, we want to be [startRow,endRow] normally  
  12.      // it is [startRow,endRow) and if startRow=endRow we get nothing.  
  13. //get式的scan为-1  
  14.      this.isScan = scan.isGetScan() ? -1 : 0;  
  15.   
  16.      // synchronize on scannerReadPoints so that nobody calculates  
  17.      // getSmallestReadPoint, before scannerReadPoints is updated.  
  18. //支持脏读,默认COMMITTED才能读  
  19.      IsolationLevel isolationLevel = scan.getIsolationLevel();  
  20.      synchronized(scannerReadPoints) {  
  21.        if (isolationLevel == IsolationLevel.READ_UNCOMMITTED) {  
  22.          // This scan can read even uncommitted transactions  
  23.          this.readPt = Long.MAX_VALUE;  
  24.          MultiVersionConsistencyControl.setThreadReadPoint(this.readPt);  
  25.        } else {  
  26.          this.readPt = MultiVersionConsistencyControl.resetThreadReadPoint(mvcc);  
  27.        }  
  28.        scannerReadPoints.put(thisthis.readPt);  
  29.      }  
  30.   
  31.      .....  
  32. //每个需要scan的store构造scanner  
  33.      for (Map.Entry<byte[], NavigableSet<byte[]>> entry :  
  34.          scan.getFamilyMap().entrySet()) {  
  35.        Store store = stores.get(entry.getKey());  
  36.        StoreScanner scanner = store.getScanner(scan, entry.getValue());  
  37.        scanners.add(scanner);  
  38.      }  
  39. //store的scanner集合  
  40.      this.storeHeap = new KeyValueHeap(scanners, comparator);  
  41.    }  
 StoreScanner构造,columns为需要scan的列名
Java代码  收藏代码
  1.  StoreScanner(Store store, Scan scan, final NavigableSet<byte[]> columns)  
  2.                              throws IOException {  
  3.    this(store, scan.getCacheBlocks(), scan, columns, store.scanInfo.getTtl(),  
  4.        store.scanInfo.getMinVersions());  
  5.    initializeMetricNames();  
  6.    if (columns != null && scan.isRaw()) {  
  7.      throw new DoNotRetryIOException(  
  8.          "Cannot specify any column for a raw scan");  
  9.    }  
  10. //核心Query,作用是对keyvalue在next迭代的时候判断当前keyvalue是否满足条件,决定下一步是跳过当前kv,跳过当前column还是直接到下一行  
  11.    matcher = new ScanQueryMatcher(scan, store.scanInfo, columns,  
  12.        ScanType.USER_SCAN, Long.MAX_VALUE, HConstants.LATEST_TIMESTAMP,  
  13.        oldestUnexpiredTS);  
  14.   
  15.    // Pass columns to try to filter out unnecessary StoreFiles.  
  16. //这里构造了memstoreScanner和StoreFileScanner  
  17.    List<KeyValueScanner> scanners = getScannersNoCompaction();  
  18.   
  19.    Store.openScannerOps.incrementAndGet();  
  20.    Store.openedScannerNum.addAndGet(scanners.size());  
  21.   
  22.    // Seek all scanners to the start of the Row (or if the exact matching row  
  23.    // key does not exist, then to the start of the next matching Row).  
  24.    // Always check bloom filter to optimize the top row seek for delete  
  25.    // family marker.  
  26. //执行seek操作  
  27.    if (explicitColumnQuery && lazySeekEnabledGlobally) {  
  28.      for (KeyValueScanner scanner : scanners) {  
  29.        scanner.requestSeek(matcher.getStartKey(), falsetrue);  
  30.      }  
  31.    } else {  
  32.      for (KeyValueScanner scanner : scanners) {  
  33.        scanner.seek(matcher.getStartKey());  
  34.      }  
  35.    }  
  36.   
  37.    // Combine all seeked scanners with a heap  
  38. //所有scanner组合成一个KeyValueHeap,按照seek的第一个keyvalue排序,结果是按照column family顺序scan  
  39.    heap = new KeyValueHeap(scanners, store.comparator);  
  40.   
  41.    this.store.addChangedReaderObserver(this);  
  42.  }  
 Store获取所有scanner
Java代码  收藏代码
  1.  protected List<KeyValueScanner> getScanners(boolean cacheBlocks,  
  2.      boolean isGet,  
  3.      boolean isCompaction,  
  4.      ScanQueryMatcher matcher) throws IOException {  
  5.    List<StoreFile> storeFiles;  
  6.    List<KeyValueScanner> memStoreScanners;  
  7.    this.lock.readLock().lock();  
  8.    try {  
  9.      storeFiles = this.getStorefiles();  
  10. //MemstoreScanner  
  11.      memStoreScanners = this.memstore.getScanners();  
  12.    } finally {  
  13.      this.lock.readLock().unlock();  
  14.    }  
  15.   
  16.    // First the store file scanners  
  17.   
  18.    // TODO this used to get the store files in descending order,  
  19.    // but now we get them in ascending order, which I think is  
  20.    // actually more correct, since memstore get put at the end.  
  21. //StoreFileScanner集合,这里会打开HDFS文件流  
  22.    List<StoreFileScanner> sfScanners = StoreFileScanner  
  23.      .getScannersForStoreFiles(storeFiles, cacheBlocks, isGet, isCompaction, matcher);  
  24.    List<KeyValueScanner> scanners =  
  25.      new ArrayList<KeyValueScanner>(sfScanners.size()+1);  
  26.    scanners.addAll(sfScanners);  
  27.    // Then the memstore scanners  
  28.    scanners.addAll(memStoreScanners);  
  29.    return scanners;  
  30.  }  
 KeyValueHeap结构
Java代码  收藏代码
  1.  public KeyValueHeap(List<? extends KeyValueScanner> scanners,  
  2.      KVComparator comparator) throws IOException {  
  3. //scanner比较器,按照peek的第一个kv对象排序,小的scanner先扫描  
  4.    this.comparator = new KVScannerComparator(comparator);  
  5.    if (!scanners.isEmpty()) {  
  6. //scanner队列,因为同一个store可能有多个scanner  
  7.      this.heap = new PriorityQueue<KeyValueScanner>(scanners.size(),  
  8.          this.comparator);  
  9.      for (KeyValueScanner scanner : scanners) {  
  10. //之前scanner已经seek过了,所以peek可以直接取kv,如果seek到了,则添加到队列  
  11.        if (scanner.peek() != null) {  
  12.          this.heap.add(scanner);  
  13.        } else {  
  14.          scanner.close();  
  15.        }  
  16.      }  
  17. //取第一个scanner,多个scanner情况下会按照peek的一个kv对象排序,小的scanner先扫描  
  18. //其结果是优先扫描MemStore,再按照StoreFile俺sequenceId从小到大扫描  
  19.      this.current = pollRealKV();  
  20.    }  
 看看KVScannerComparator,先按kv排序,一样则按sequenceid排序
Java代码  收藏代码
  1.   public int compare(KeyValueScanner left, KeyValueScanner right) {  
  2.      int comparison = compare(left.peek(), right.peek());  
  3. //直接比较keyvalue  
  4.      if (comparison != 0) {  
  5.        return comparison;  
  6.      } else {  
  7. //如果keyvalue对象一样,这个情况很少,则按照sequenceId比较,注意MemStoreScanner有最大的id  
  8.        // Since both the keys are exactly the same, we break the tie in favor  
  9.        // of the key which came latest.  
  10.        long leftSequenceID = left.getSequenceID();  
  11.        long rightSequenceID = right.getSequenceID();  
  12.        if (leftSequenceID > rightSequenceID) {  
  13.          return -1;  
  14.        } else if (leftSequenceID < rightSequenceID) {  
  15.          return 1;  
  16.        } else {  
  17.          return 0;  
  18.        }  
  19.      }  
  20.    }  
  21.  }  
 以上就是scanner构造过程,RegionScannerImpl开始next取数据,注意这里是'Grab the next row's worth of values',就是取下一行,因为get操作只会涉及单行数据
Java代码  收藏代码
  1. private boolean nextInternal(int limit) throws IOException {  
  2.       RpcCallContext rpcCall = HBaseServer.getCurrentCall();  
  3.       while (true) {  
  4.     //client是否已经关闭连接  
  5.         if (rpcCall != null) {  
  6.           // If a user specifies a too-restrictive or too-slow scanner, the  
  7.           // client might time out and disconnect while the server side  
  8.           // is still processing the request. We should abort aggressively  
  9.           // in that case.  
  10.           rpcCall.throwExceptionIfCallerDisconnected();  
  11.         }  
  12.     //从Heap中拿当前seek到的row  
  13.         byte [] currentRow = peekRow();  
  14.     //判断是否是stopRow,currentRow为null或currentRow大于等于stopRow,所以这里实现了‘)’操作  
  15.         if (isStopRow(currentRow)) {  
  16.           if (filter != null && filter.hasFilterRow()) {  
  17.             filter.filterRow(results);  
  18.           }  
  19.           if (filter != null && filter.filterRow()) {  
  20.             results.clear();  
  21.           }  
  22.   
  23.           return false;  
  24.         }   
  25.     //filter行过滤  
  26.     else if (filterRowKey(currentRow)) {  
  27.           nextRow(currentRow);  
  28.         } else {  
  29.           byte [] nextRow;  
  30.         //内循环,从heap中取kv数据,直到满足limit或者跨行,因为这里只去单行数据  
  31.           do {  
  32.         //从heap中批量获取keyvalue  
  33.             this.storeHeap.next(results, limit - results.size());  
  34.         //取满limit,默认没限制,limit为-1  
  35.             if (limit > 0 && results.size() == limit) {  
  36.               if (this.filter != null && filter.hasFilterRow()) {  
  37.                 throw new IncompatibleFilterException(  
  38.                   "Filter with filterRow(List<KeyValue>) incompatible with scan with limit!");  
  39.               }  
  40.               return true// we are expecting more yes, but also limited to how many we can return.  
  41.             }  
  42.           } while (Bytes.equals(currentRow, nextRow = peekRow()));  
  43.   
  44.           final boolean stopRow = isStopRow(nextRow);  
  45.   
  46.           // now that we have an entire row, lets process with a filters:  
  47.   
  48.           // first filter with the filterRow(List)  
  49.         //过滤  
  50.           if (filter != null && filter.hasFilterRow()) {  
  51.             filter.filterRow(results);  
  52.           }  
  53.         ......  
  54.           return !stopRow;  
  55.         }  
  56.       }  
  57.     }  
 RegionScannerImpl的KeyValueHeap取数,这个KeyValueHeap里的scanner都是StoreScanner,按照seek之后的第一个keyvalue排序,就是按照column family顺序从小到大排序
Java代码  收藏代码
  1. public boolean next(List<KeyValue> result, int limit) throws IOException {  
  2.     if (this.current == null) {  
  3.       return false;  
  4.     }  
  5.     InternalScanner currentAsInternal = (InternalScanner)this.current;  
  6.     //第一个StoreScanner取数  
  7.     boolean mayContainMoreRows = currentAsInternal.next(result, limit);  
  8.     //取完之后的peek值  
  9.     KeyValue pee = this.current.peek();  
  10.     /* 
  11.      * By definition, any InternalScanner must return false only when it has no 
  12.      * further rows to be fetched. So, we can close a scanner if it returns 
  13.      * false. All existing implementations seem to be fine with this. It is much 
  14.      * more efficient to close scanners which are not needed than keep them in 
  15.      * the heap. This is also required for certain optimizations. 
  16.      */  
  17.     //scan结束,关闭scanner  
  18.     if (pee == null || !mayContainMoreRows) {  
  19.       this.current.close();  
  20.     }   
  21.     //当前scanner还没结束,继续  
  22.     else {  
  23.       this.heap.add(this.current);  
  24.     }  
  25.     //下一个scanner  
  26.     this.current = pollRealKV();  
  27.     return (this.current != null);  
  28.   }  
 StoreScanner取数
Java代码  收藏代码
  1. public synchronized boolean next(List<KeyValue> outResult, int limit) throws IOException {  
  2.   
  3.     ......  
  4.   
  5.     // only call setRow if the row changes; avoids confusing the query matcher  
  6.     // if scanning intra-row  
  7.     //当前row  
  8.     if ((matcher.row == null) || !peeked.matchingRow(matcher.row)) {  
  9.       matcher.setRow(peeked.getRow());  
  10.     }  
  11.   
  12.     KeyValue kv;  
  13.     KeyValue prevKV = null;  
  14.     List<KeyValue> results = new ArrayList<KeyValue>();  
  15.   
  16.     // Only do a sanity-check if store and comparator are available.  
  17.     KeyValue.KVComparator comparator =  
  18.         store != null ? store.getComparator() : null;  
  19.   
  20.     //从heap中取数,直到满足limit,或者scan结束,或者matcher认为不需要再往下扫描,比如column取满数据了  
  21.     LOOP: while((kv = this.heap.peek()) != null) {  
  22.       // Check that the heap gives us KVs in an increasing order.  
  23.       if (prevKV != null && comparator != null  
  24.           && comparator.compare(prevKV, kv) > 0) {  
  25.         throw new IOException("Key " + prevKV + " followed by a " +  
  26.             "smaller key " + kv + " in cf " + store);  
  27.       }  
  28.       prevKV = kv;  
  29.     //matcher决定是接着scan还是结束  
  30.       ScanQueryMatcher.MatchCode qcode = matcher.match(kv);  
  31.       switch(qcode) {  
  32.     //当前keyvalue有效,继续往下  
  33.         case INCLUDE:  
  34.         case INCLUDE_AND_SEEK_NEXT_ROW:  
  35.         case INCLUDE_AND_SEEK_NEXT_COL:  
  36.         //添加到result  
  37.           Filter f = matcher.getFilter();  
  38.           results.add(f == null ? kv : f.transform(kv));  
  39.         //需要换行,检查下是否还需要下行数据,对于get请求,这里会直接返回,因为单行数据就够了  
  40.           if (qcode == ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_ROW) {  
  41.             if (!matcher.moreRowsMayExistAfter(kv)) {  
  42.               outResult.addAll(results);  
  43.               return false;  
  44.             }  
  45.             reseek(matcher.getKeyForNextRow(kv));  
  46.           }   
  47.         //取下一个column,前一个column取满了     
  48.     else if (qcode == ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL) {  
  49.             reseek(matcher.getKeyForNextColumn(kv));  
  50.           }   
  51.         //当前column,取下一个version    
  52.     else {  
  53.             this.heap.next();  
  54.           }  
  55.   
  56.           RegionMetricsStorage.incrNumericMetric(metricNameGetSize, kv.getLength());  
  57.         //limit满直接返回  
  58.           if (limit > 0 && (results.size() == limit)) {  
  59.             break LOOP;  
  60.           }  
  61.           continue;  
  62.   
  63.         case DONE:  
  64.           // copy jazz  
  65.           outResult.addAll(results);  
  66.           return true;  
  67.   
  68.         case DONE_SCAN:  
  69.           close();  
  70.   
  71.           // copy jazz  
  72.           outResult.addAll(results);  
  73.   
  74.           return false;  
  75.   
  76.        ......  
  77.       }  
  78.     }  
  79.   
  80.     if (!results.isEmpty()) {  
  81.       // copy jazz  
  82.       outResult.addAll(results);  
  83.       return true;  
  84.     }  
  85.   
  86.     // No more keys  
  87.     close();  
  88.     return false;  
  89.   }  
 match过程
Java代码  收藏代码
  1. public MatchCode match(KeyValue kv) throws IOException {  
  2.     .....  
  3. //和开始row比较  
  4.    int ret = this.rowComparator.compareRows(row, 0, row.length,  
  5.        bytes, offset, rowLength);  
  6. //如果当前row比开始row大,表示开始row scan结束  
  7.    if (ret <= -1) {  
  8.      return MatchCode.DONE;  
  9.    }   
  10. //如果当前row小于开始row,往下seek直到我们感兴趣的row  
  11. else if (ret >= 1) {  
  12.      // could optimize this, if necessary?  
  13.      // Could also be called SEEK_TO_CURRENT_ROW, but this  
  14.      // should be rare/never happens.  
  15.      return MatchCode.SEEK_NEXT_ROW;  
  16.    }  
  17. //行匹配  
  18.    // optimize case.  
  19.    if (this.stickyNextRow)  
  20.        return MatchCode.SEEK_NEXT_ROW;  
  21. //所有column都处理完了,处理下一行  
  22.    if (this.columns.done()) {  
  23.      stickyNextRow = true;  
  24.      return MatchCode.SEEK_NEXT_ROW;  
  25.    }  
  26.   
  27.    //Passing rowLength  
  28.    offset += rowLength;  
  29.   
  30.    //Skipping family  
  31.    byte familyLength = bytes [offset];  
  32.    offset += familyLength + 1;  
  33.   
  34.    int qualLength = keyLength + KeyValue.ROW_OFFSET -  
  35.      (offset - initialOffset) - KeyValue.TIMESTAMP_TYPE_SIZE;  
  36.   
  37.    long timestamp = kv.getTimestamp();  
  38.    // check for early out based on timestamp alone  
  39. //当前keyvalue的timestamp是否已经没用,如果是,则当前column可以不用处理了,因为后续version的数据timestamp只会更小  
  40. //让columnChecker决定是否需要取下一列或下一行  
  41.    if (columns.isDone(timestamp)) {  
  42.        return columns.getNextRowOrNextColumn(bytes, offset, qualLength);  
  43.    }  
  44.   
  45. .......  
  46. //匹配时间  
  47.    int timestampComparison = tr.compare(timestamp);  
  48. //超过了,则跳过当前keyvalue  
  49.    if (timestampComparison >= 1) {  
  50.      return MatchCode.SKIP;  
  51.    }   
  52. //不够,则当前column可以不用处理了,让columnChecker决定是否需要取下一列或下一行  
  53. else if (timestampComparison <= -1) {  
  54.      return columns.getNextRowOrNextColumn(bytes, offset, qualLength);  
  55.    }  
  56.   
  57.     ....  
  58. //检查column取数是否已完成,内部会维护一个ColumnCount保留匹配的version数量  
  59.    MatchCode colChecker = columns.checkColumn(bytes, offset, qualLength,  
  60.        timestamp, type, kv.getMemstoreTS() > maxReadPointToTrackVersions);  
  61.    /* 
  62.     * According to current implementation, colChecker can only be 
  63.     * SEEK_NEXT_COL, SEEK_NEXT_ROW, SKIP or INCLUDE. Therefore, always return 
  64.     * the MatchCode. If it is SEEK_NEXT_ROW, also set stickyNextRow. 
  65.     */  
  66.    if (colChecker == MatchCode.SEEK_NEXT_ROW) {  
  67.      stickyNextRow = true;  
  68.    }  
  69.    return colChecker;  
  70.   
  71.  }  
 以指定column方式get的ExplicitColumnTracker为例,看看如何checkColumn,ColumnChecker内部维护一个column列表和一个index指针,代表当前处理的column,按column顺序处理,每个处理完的column会从列表中remove掉,直到column都处理完,则认为该行数据都处理完了
Java代码  收藏代码
  1. public ScanQueryMatcher.MatchCode checkColumn(byte [] bytes, int offset,  
  2.       int length, long timestamp, byte type, boolean ignoreCount) {  
  3.     // delete markers should never be passed to an  
  4.     // *Explicit*ColumnTracker  
  5.     assert !KeyValue.isDelete(type);  
  6.     do {  
  7.       // No more columns left, we are done with this query  
  8.     //所有column已经处理完了,则换行  
  9.       if(this.columns.size() == 0) {  
  10.         return ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW; // done_row  
  11.       }  
  12.   
  13.       // No more columns to match against, done with storefile  
  14.     //column处理完,则换行  
  15.       if(this.column == null) {  
  16.         return ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW; // done_row  
  17.       }  
  18.   
  19.       // Compare specific column to current column  
  20.     //当前处理column和keyvalue匹配列名  
  21.       int ret = Bytes.compareTo(column.getBuffer(), column.getOffset(),  
  22.           column.getLength(), bytes, offset, length);  
  23.   
  24.       // Column Matches. If it is not a duplicate key, increment the version count  
  25.       // and include.  
  26.     //列名匹配,则处理之  
  27.       if(ret == 0) {  
  28.         if (ignoreCount) return ScanQueryMatcher.MatchCode.INCLUDE;  
  29.   
  30.         //If column matches, check if it is a duplicate timestamp  
  31.     //相同timestamp,跳过  
  32.         if (sameAsPreviousTS(timestamp)) {  
  33.           //If duplicate, skip this Key  
  34.           return ScanQueryMatcher.MatchCode.SKIP;  
  35.         }  
  36.     //count递增  
  37.         int count = this.column.increment();  
  38.     //version数取够了或者timestamp太小,则该column可以跳过了  
  39.         if(count >= maxVersions || (count >= minVersions && isExpired(timestamp))) {  
  40.           // Done with versions for this column  
  41.           // Note: because we are done with this column, and are removing  
  42.           // it from columns, we don't do a ++this.index. The index stays  
  43.           // the same but the columns have shifted within the array such  
  44.           // that index now points to the next column we are interested in.  
  45.         //先删掉  
  46.           this.columns.remove(this.index);  
  47.   
  48.           resetTS();  
  49.         //删完之后比较数量,如果和index一致,则认为所有column都已处理完成  
  50.           if (this.columns.size() == this.index) {  
  51.             // We have served all the requested columns.  
  52.             this.column = null;  
  53.             return ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_ROW;  
  54.           }   
  55.         //给下一个column处理做准备     
  56.     else {  
  57.             // We are done with current column; advance to next column  
  58.             // of interest.  
  59.             this.column = this.columns.get(this.index);  
  60.             return ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL;  
  61.           }  
  62.         } else {  
  63.           setTS(timestamp);  
  64.         }  
  65.     //数量还不够,继续往下scan  
  66.         return ScanQueryMatcher.MatchCode.INCLUDE;  
  67.       }  
  68.     //当前keyvalue和column不匹配  
  69.       resetTS();  
  70.     //当前keyvalue的column小于希望的column,跳过读下一个column  
  71.       if (ret > 0) {  
  72.         // The current KV is smaller than the column the ExplicitColumnTracker  
  73.         // is interested in, so seek to that column of interest.  
  74.         return ScanQueryMatcher.MatchCode.SEEK_NEXT_COL;  
  75.       }  
  76.   
  77.       // The current KV is bigger than the column the ExplicitColumnTracker  
  78.       // is interested in. That means there is no more data for the column  
  79.       // of interest. Advance the ExplicitColumnTracker state to next  
  80.       // column of interest, and check again.  
  81.     //当前keyvalue的column大于希望的column,则继续处理下一个column,不理解  
  82.       if (ret <= -1) {  
  83.         if (++this.index >= this.columns.size()) {  
  84.           // No more to match, do not include, done with this row.  
  85.           return ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW; // done_row  
  86.         }  
  87.         // This is the recursive case.  
  88.         this.column = this.columns.get(this.index);  
  89.       }  
  90.     } while(true);  
  91.   }  
 KeyValueHeap迭代,保证keyvalue是按顺序scan的,有可能多个scanner之间会来回切换
Java代码  收藏代码
  1. public KeyValue next()  throws IOException {  
  2.     if(this.current == null) {  
  3.       return null;  
  4.     }  
  5.     //当前值  
  6.     KeyValue kvReturn = this.current.next();  
  7.     //当前scanner的下一个keyvalue  
  8.     KeyValue kvNext = this.current.peek();  
  9.     //当前scanner结束,换一个scanner  
  10.     if (kvNext == null) {  
  11.       this.current.close();  
  12.       this.current = pollRealKV();  
  13.     }   
  14.     //当前scanner的keyvalue再和其他scanner的peek值比较,如果大于则切换到其他scanner,保证keyvalue是从小到大排序  
  15.     else {  
  16.       KeyValueScanner topScanner = this.heap.peek();  
  17.       if (topScanner == null ||  
  18.           this.comparator.compare(kvNext, topScanner.peek()) >= 0) {  
  19.         this.heap.add(this.current);  
  20.         this.current = pollRealKV();  
  21.       }  
  22.     }  
  23.     return kvReturn;  
  24.   }  
 以MemStoreScanner来看看next取数,在keset和snapshot中切换
Java代码  收藏代码
  1.    public synchronized KeyValue next() {  
  2.      if (theNext == null) {  
  3.          return null;  
  4.      }  
  5. //老的值  
  6.      final KeyValue ret = theNext;  
  7.   
  8.      // Advance one of the iterators  
  9. //从kvset中迭代  
  10.      if (theNext == kvsetNextRow) {  
  11.        kvsetNextRow = getNext(kvsetIt);  
  12.      }   
  13. //从snapshot迭代  
  14. else {  
  15.        snapshotNextRow = getNext(snapshotIt);  
  16.      }  
  17.   
  18.      // Calculate the next value  
  19. //取小的那个  
  20.      theNext = getLowest(kvsetNextRow, snapshotNextRow);  
  21.   
  22.      //long readpoint = ReadWriteConsistencyControl.getThreadReadPoint();  
  23.      //DebugPrint.println(" MS@" + hashCode() + " next: " + theNext + " next_next: " +  
  24.      //    getLowest() + " threadpoint=" + readpoint);  
  25.      return ret;  
  26.    }  
 以上就是Get的过程,主要步骤
1.scanner组装
2.迭代时,多个scanner之间需要保证keyvalue对象按顺序scan出来,核心是PriorityQueue+KVScannerComparator
3.ScanQueryMatcher来决定当前keyvalue对象是否可用,下一个请求如何处理,跳列还是跳行
4.ColumnChecker来决定当前column是否已经处理完毕,下一个请求如何处理,跳列还是跳行

0 0
原创粉丝点击