@Override public Cell getKey() { assertSeeked(); // Create a new object so that this getKey is cached as firstKey, lastKey ObjectIntPair<ByteBuffer> keyPair = new ObjectIntPair<>(); blockBuffer.asSubByteBuffer(blockBuffer.position() + KEY_VALUE_LEN_SIZE, currKeyLen, keyPair); ByteBuffer keyBuf = keyPair.getFirst(); if (keyBuf.hasArray()) { return new KeyValue.KeyOnlyKeyValue(keyBuf.array(), keyBuf.arrayOffset() + keyPair.getSecond(), currKeyLen); } else { // Better to do a copy here instead of holding on to this BB so that // we could release the blocks referring to this key. This key is specifically used // in HalfStoreFileReader to get the firstkey and lastkey by creating a new scanner // every time. So holding onto the BB (incase of DBB) is not advised here. byte[] key = new byte[currKeyLen]; ByteBufferUtils.copyFromBufferToArray(key, keyBuf, keyPair.getSecond(), 0, currKeyLen); return new KeyValue.KeyOnlyKeyValue(key, 0, currKeyLen); } }
/** * Check key and value lengths are wholesome. */ protected final void checkKeyValueLen() { if (checkKeyLen(this.currKeyLen) || checkLen(this.currValueLen)) { throw new IllegalStateException("Invalid currKeyLen " + this.currKeyLen + " or currValueLen " + this.currValueLen + ". Block offset: " + this.curBlock.getOffset() + ", block length: " + this.blockBuffer.limit() + ", position: " + this.blockBuffer.position() + " (without header)."); } }
klen = (int)(ll >> Integer.SIZE); vlen = (int)(Bytes.MASK_FOR_LOWER_INT_IN_LONG ^ ll); if (checkKeyLen(klen) || checkLen(vlen)) { throw new IllegalStateException("Invalid klen " + klen + " or vlen " + vlen + ". Block offset: " if (checkLen(tlen)) { throw new IllegalStateException("Invalid tlen " + tlen + ". Block offset: " + curBlock.getOffset() + ", block length: " + blockBuffer.limit() + ", position: " readMvccVersion(offsetFromPos); readKeyValueLen(); return 1; // non exact match. blockBuffer.moveBack(lastKeyValueSize); readKeyValueLen(); if (lastKeyValueSize == -1 && blockBuffer.position() == 0) { return HConstants.INDEX_KEY_MAGIC; readKeyValueLen(); return 1; // didn't exactly find it.
@Override public int reseekTo(Cell key) throws IOException { int compared; if (isSeeked()) { compared = compareKey(reader.getComparator(), key); if (compared < 1) { // If the required key is less than or equal to current key, then // don't do anything. return compared; } else { // The comparison with no_next_index_key has to be checked if (this.nextIndexedKey != null && (this.nextIndexedKey == KeyValueScanner.NO_NEXT_INDEXED_KEY || PrivateCellUtil .compareKeyIgnoresMvcc(reader.getComparator(), key, nextIndexedKey) < 0)) { // The reader shall continue to scan the current data block instead // of querying the // block index as long as it knows the target key is strictly // smaller than // the next indexed key or the current data block is the last data // block. return loadBlockAndSeekToKey(this.curBlock, nextIndexedKey, false, key, false); } } } // Don't rewind on a reseek operation, because reseek implies that we are // always going forward in the file. return seekTo(key, false); }
protected void readKeyValueLen() { // This is a hot method. We go out of our way to make this method short so it can be // inlined and is not too big to compile. We also manage position in ByteBuffer ourselves // because it is faster than going via range-checked ByteBuffer methods or going through a // byte buffer array a byte at a time. // Get a long at a time rather than read two individual ints. In micro-benchmarking, even // with the extra bit-fiddling, this is order-of-magnitude faster than getting two ints. // Trying to imitate what was done - need to profile if this is better or // earlier way is better by doing mark and reset? // But ensure that you read long instead of two ints long ll = blockBuffer.getLongAfterPosition(0); // Read top half as an int of key length and bottom int as value length this.currKeyLen = (int)(ll >> Integer.SIZE); this.currValueLen = (int)(Bytes.MASK_FOR_LOWER_INT_IN_LONG ^ ll); checkKeyValueLen(); // Move position past the key and value lengths and then beyond the key and value int p = (Bytes.SIZEOF_LONG + currKeyLen + currValueLen); if (reader.getFileContext().isIncludesTags()) { // Tags length is a short. this.currTagsLen = blockBuffer.getShortAfterPosition(p); checkTagsLen(); p += (Bytes.SIZEOF_SHORT + currTagsLen); } readMvccVersion(p); }
/** * Create a Scanner on this file. No seeks or reads are done on creation. Call * {@link HFileScanner#seekTo(Cell)} to position an start the read. There is * nothing to clean up in a Scanner. Letting go of your references to the * scanner is sufficient. * @param cacheBlocks * True if we should cache blocks read in by this scanner. * @param pread * Use positional read rather than seek+read if true (pread is better * for random reads, seek+read is better scanning). * @param isCompaction * is scanner being used for a compaction? * @return Scanner on this file. */ @Override public HFileScanner getScanner(boolean cacheBlocks, final boolean pread, final boolean isCompaction) { if (dataBlockEncoder.useEncodedScanner()) { return new EncodedScanner(this, cacheBlocks, pread, isCompaction, this.hfileContext); } return new HFileScannerImpl(this, cacheBlocks, pread, isCompaction); }
/** * Go to the next key/value in the block section. Loads the next block if * necessary. If successful, {@link #getKey()} and {@link #getValue()} can * be called. * * @return true if successfully navigated to the next key/value */ @Override public boolean next() throws IOException { // This is a hot method so extreme measures taken to ensure it is small and inlineable. // Checked by setting: -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining -XX:+PrintCompilation assertSeeked(); positionThisBlockBuffer(); return _next(); }
/** * Read mvcc. Does checks to see if we even need to read the mvcc at all. * @param offsetFromPos */ protected void readMvccVersion(final int offsetFromPos) { // See if we even need to decode mvcc. if (!this.reader.shouldIncludeMemStoreTS()) return; if (!this.reader.isDecodeMemStoreTS()) { currMemstoreTS = 0; currMemstoreTSLen = 1; return; } _readMvccVersion(offsetFromPos); }
private final void checkTagsLen() { if (checkLen(this.currTagsLen)) { throw new IllegalStateException("Invalid currTagsLen " + this.currTagsLen + ". Block offset: " + curBlock.getOffset() + ", block length: " + this.blockBuffer.limit() + ", position: " + this.blockBuffer.position() + " (without header)."); } }
protected int loadBlockAndSeekToKey(HFileBlock seekToBlock, Cell nextIndexedKey, boolean rewind, Cell key, boolean seekBefore) throws IOException { if (this.curBlock == null || this.curBlock.getOffset() != seekToBlock.getOffset()) { updateCurrentBlock(seekToBlock); } else if (rewind) { blockBuffer.rewind(); } // Update the nextIndexedKey this.nextIndexedKey = nextIndexedKey; return blockSeek(key, seekBefore); }
@Override public ByteBuffer getValue() { assertSeeked(); // Okie to create new Pair. Not used in hot path ObjectIntPair<ByteBuffer> valuePair = new ObjectIntPair<>(); this.blockBuffer.asSubByteBuffer(blockBuffer.position() + KEY_VALUE_LEN_SIZE + currKeyLen, currValueLen, valuePair); ByteBuffer valBuf = valuePair.getFirst().duplicate(); valBuf.position(valuePair.getSecond()); valBuf.limit(currValueLen + valuePair.getSecond()); return valBuf.slice(); }