/** * Add key/value to file. Keys must be added in an order that agrees with the Comparator passed on * construction. * * @param kv KeyValue to add. Cannot be empty nor null. * @throws IOException */ @Override public void append(final KeyValue kv) throws IOException { byte[] key = kv.getBuffer(); int koffset = kv.getKeyOffset(); int klength = kv.getKeyLength(); byte[] value = kv.getValueArray(); int voffset = kv.getValueOffset(); int vlength = kv.getValueLength(); boolean dupKey = checkKey(key, koffset, klength); checkValue(value, voffset, vlength); if (!dupKey) { checkBlockBoundary(); } if (!fsBlockWriter.isWriting()) newBlock(); fsBlockWriter.write(kv); totalKeyLength += klength; totalValueLength += vlength; // Are we the first key in this block? if (firstKeyInBlock == null) { // Copy the key. firstKeyInBlock = new byte[klength]; System.arraycopy(key, koffset, firstKeyInBlock, 0, klength); } lastKeyBuffer = key; lastKeyOffset = koffset; lastKeyLength = klength; entryCount++; this.maxMemstoreTS = Math.max(this.maxMemstoreTS, kv.getMvccVersion()); }
static boolean reseekAtOrAfter(HFileScanner s, KeyValue k) throws IOException { // This function is similar to seekAtOrAfter function int result = s.reseekTo(k.getBuffer(), k.getKeyOffset(), k.getKeyLength()); if (result <= 0) { return true; } else { // passed KV is larger than current KV in file, if there is a next // it is after, if not then this scanner is done. return s.next(); } }
@Test public void testNextOnSample() throws IOException { List<KeyValue> sampleKv = generator.generateTestKeyValues(NUMBER_OF_KV, includesTags); for (DataBlockEncoding encoding : DataBlockEncoding.values()) { // Off heap block data support not added for PREFIX_TREE DBE yet. // TODO remove this once support is added. HBASE-12298 if (this.useOffheapData && encoding == DataBlockEncoding.PREFIX_TREE) continue; if (encoding.getEncoder() == null) { continue; } DataBlockEncoder encoder = encoding.getEncoder(); ByteBuffer encodedBuffer = encodeKeyValues( encoding, sampleKv, getEncodingContext(Compression.Algorithm.NONE, encoding), this.useOffheapData); HFileContext meta = new HFileContextBuilder() .withHBaseCheckSum(false) .withIncludesMvcc(includesMemstoreTS) .withIncludesTags(includesTags) .withCompression(Compression.Algorithm.NONE) .build(); DataBlockEncoder.EncodedSeeker seeker = encoder.createSeeker( CellComparator.COMPARATOR, encoder.newDataBlockDecodingContext(meta)); seeker.setCurrentBuffer(new SingleByteBuff(encodedBuffer)); int i = 0; do { KeyValue expectedKeyValue = sampleKv.get(i); Cell cell = seeker.getCell(); if (CellComparator.COMPARATOR.compareKeyIgnoresMvcc(expectedKeyValue, cell) != 0) { int commonPrefix = CellUtil.findCommonPrefixInFlatKey(expectedKeyValue, cell, false, true); fail( String.format( "next() produces wrong results " + "encoder: %s i: %d commonPrefix: %d" + "\n expected %s\n actual %s", encoder.toString(), i, commonPrefix, Bytes.toStringBinary( expectedKeyValue.getBuffer(), expectedKeyValue.getKeyOffset(), expectedKeyValue.getKeyLength()), CellUtil.toString(cell, false))); } i++; } while (seeker.next()); } }
/** * Add key/value to file. Keys must be added in an order that agrees with the Comparator passed on * construction. * * @param kv KeyValue to add. Cannot be empty nor null. * @throws IOException */ @Override public void append(final KeyValue kv) throws IOException { append( kv.getMemstoreTS(), kv.getBuffer(), kv.getKeyOffset(), kv.getKeyLength(), kv.getBuffer(), kv.getValueOffset(), kv.getValueLength()); this.maxMemstoreTS = Math.max(this.maxMemstoreTS, kv.getMemstoreTS()); }
/** * @param s * @param k * @return * @throws IOException */ public static boolean seekAtOrAfter(HFileScanner s, KeyValue k) throws IOException { int result = s.seekTo(k.getBuffer(), k.getKeyOffset(), k.getKeyLength()); if (result < 0) { // Passed KV is smaller than first KV in file, work from start of file return s.seekTo(); } else if (result > 0) { // Passed KV is larger than current KV in file, if there is a next // it is the "after", if not then this scanner is done. return s.next(); } // Seeked to the exact key return true; }
/** * Write out a split reference. Package local so it doesnt leak out of regionserver. * * @param hri {@link HRegionInfo} of the destination * @param familyName Column Family Name * @param f File to split. * @param splitRow Split Row * @param top True if we are referring to the top half of the hfile. * @return Path to created reference. * @throws IOException */ Path splitStoreFile( final HRegionInfo hri, final String familyName, final StoreFile f, final byte[] splitRow, final boolean top) throws IOException { // Check whether the split row lies in the range of the store file // If it is outside the range, return directly. if (!isIndexTable()) { if (top) { // check if larger than last key. KeyValue splitKey = KeyValue.createFirstOnRow(splitRow); byte[] lastKey = f.createReader().getLastKey(); // If lastKey is null means storefile is empty. if (lastKey == null) return null; if (f.getReader() .getComparator() .compareFlatKey( splitKey.getBuffer(), splitKey.getKeyOffset(), splitKey.getKeyLength(), lastKey, 0, lastKey.length) > 0) { return null; } } else { // check if smaller than first key KeyValue splitKey = KeyValue.createLastOnRow(splitRow); byte[] firstKey = f.createReader().getFirstKey(); // If firstKey is null means storefile is empty. if (firstKey == null) return null; if (f.getReader() .getComparator() .compareFlatKey( splitKey.getBuffer(), splitKey.getKeyOffset(), splitKey.getKeyLength(), firstKey, 0, firstKey.length) < 0) { return null; } } f.getReader().close(true); } Path splitDir = new Path(getSplitsDir(hri), familyName); // A reference to the bottom half of the hsf store file. Reference r = top ? Reference.createTopReference(splitRow) : Reference.createBottomReference(splitRow); // Add the referred-to regions name as a dot separated suffix. // See REF_NAME_REGEX regex above. The referred-to regions name is // up in the path of the passed in <code>f</code> -- parentdir is family, // then the directory above is the region name. String parentRegionName = regionInfo.getEncodedName(); // Write reference with same file id only with the other region name as // suffix and into the new region location (under same family). Path p = new Path(splitDir, f.getPath().getName() + "." + parentRegionName); return r.write(fs, p); }