001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.regionserver; 019 020import static org.apache.hadoop.hbase.io.crypto.ManagedKeyData.KEY_SPACE_GLOBAL; 021 022import java.io.IOException; 023import java.io.UnsupportedEncodingException; 024import java.net.URLEncoder; 025import java.util.Collection; 026import java.util.Collections; 027import java.util.HashSet; 028import java.util.Map; 029import java.util.Optional; 030import java.util.OptionalLong; 031import java.util.Set; 032import java.util.concurrent.atomic.AtomicBoolean; 033import org.apache.hadoop.conf.Configuration; 034import org.apache.hadoop.fs.FSDataInputStream; 035import org.apache.hadoop.fs.FileSystem; 036import org.apache.hadoop.fs.Path; 037import org.apache.hadoop.hbase.CellComparator; 038import org.apache.hadoop.hbase.ExtendedCell; 039import org.apache.hadoop.hbase.HConstants; 040import org.apache.hadoop.hbase.HDFSBlocksDistribution; 041import org.apache.hadoop.hbase.io.TimeRange; 042import org.apache.hadoop.hbase.io.hfile.BlockType; 043import org.apache.hadoop.hbase.io.hfile.BloomFilterMetrics; 044import org.apache.hadoop.hbase.io.hfile.CacheConfig; 045import org.apache.hadoop.hbase.io.hfile.HFile; 046import org.apache.hadoop.hbase.io.hfile.ReaderContext; 047import org.apache.hadoop.hbase.io.hfile.ReaderContext.ReaderType; 048import org.apache.hadoop.hbase.keymeta.ManagedKeyDataCache; 049import org.apache.hadoop.hbase.keymeta.SystemKeyCache; 050import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTracker; 051import org.apache.hadoop.hbase.util.BloomFilterFactory; 052import org.apache.hadoop.hbase.util.Bytes; 053import org.apache.yetus.audience.InterfaceAudience; 054import org.slf4j.Logger; 055import org.slf4j.LoggerFactory; 056 057import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 058import org.apache.hbase.thirdparty.org.apache.commons.collections4.CollectionUtils; 059 060import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 061 062/** 063 * A Store data file. Stores usually have one or more of these files. They are produced by flushing 064 * the memstore to disk. To create, instantiate a writer using {@link StoreFileWriter.Builder} and 065 * append data. Be sure to add any metadata before calling close on the Writer (Use the 066 * appendMetadata convenience methods). On close, a StoreFile is sitting in the Filesystem. To refer 067 * to it, create a StoreFile instance passing filesystem and path. To read, call 068 * {@link #initReader()} 069 * <p> 070 * StoreFiles may also reference store files in another Store. The reason for this weird pattern 071 * where you use a different instance for the writer and a reader is that we write once but read a 072 * lot more. 073 */ 074@InterfaceAudience.Private 075public class HStoreFile implements StoreFile { 076 077 private static final Logger LOG = LoggerFactory.getLogger(HStoreFile.class.getName()); 078 079 // Keys for fileinfo values in HFile 080 081 /** Max Sequence ID in FileInfo */ 082 public static final byte[] MAX_SEQ_ID_KEY = Bytes.toBytes("MAX_SEQ_ID_KEY"); 083 084 /** Major compaction flag in FileInfo */ 085 public static final byte[] MAJOR_COMPACTION_KEY = Bytes.toBytes("MAJOR_COMPACTION_KEY"); 086 087 /** Minor compaction flag in FileInfo */ 088 public static final byte[] EXCLUDE_FROM_MINOR_COMPACTION_KEY = 089 Bytes.toBytes("EXCLUDE_FROM_MINOR_COMPACTION"); 090 091 /** 092 * Key for compaction event which contains the compacted storefiles in FileInfo 093 */ 094 public static final byte[] COMPACTION_EVENT_KEY = Bytes.toBytes("COMPACTION_EVENT_KEY"); 095 096 /** Bloom filter Type in FileInfo */ 097 public static final byte[] BLOOM_FILTER_TYPE_KEY = Bytes.toBytes("BLOOM_FILTER_TYPE"); 098 099 /** Bloom filter param in FileInfo */ 100 public static final byte[] BLOOM_FILTER_PARAM_KEY = Bytes.toBytes("BLOOM_FILTER_PARAM"); 101 102 /** Delete Family Count in FileInfo */ 103 public static final byte[] DELETE_FAMILY_COUNT = Bytes.toBytes("DELETE_FAMILY_COUNT"); 104 105 /** Last Bloom filter key in FileInfo */ 106 public static final byte[] LAST_BLOOM_KEY = Bytes.toBytes("LAST_BLOOM_KEY"); 107 108 /** Key for Timerange information in metadata */ 109 public static final byte[] TIMERANGE_KEY = Bytes.toBytes("TIMERANGE"); 110 111 /** Key for timestamp of earliest-put in metadata */ 112 public static final byte[] EARLIEST_PUT_TS = Bytes.toBytes("EARLIEST_PUT_TS"); 113 114 /** Key for the number of mob cells in metadata */ 115 public static final byte[] MOB_CELLS_COUNT = Bytes.toBytes("MOB_CELLS_COUNT"); 116 117 /** Null data */ 118 public static final byte[] NULL_VALUE = new byte[] { 0 }; 119 120 /** Key for the list of MOB file references */ 121 public static final byte[] MOB_FILE_REFS = Bytes.toBytes("MOB_FILE_REFS"); 122 123 /** Meta key set when store file is a result of a bulk load */ 124 public static final byte[] BULKLOAD_TASK_KEY = Bytes.toBytes("BULKLOAD_SOURCE_TASK"); 125 public static final byte[] BULKLOAD_TIME_KEY = Bytes.toBytes("BULKLOAD_TIMESTAMP"); 126 127 /** 128 * Key for skipping resetting sequence id in metadata. For bulk loaded hfiles, the scanner resets 129 * the cell seqId with the latest one, if this metadata is set as true, the reset is skipped. 130 */ 131 public static final byte[] SKIP_RESET_SEQ_ID = Bytes.toBytes("SKIP_RESET_SEQ_ID"); 132 133 public static final byte[] HISTORICAL_KEY = Bytes.toBytes("HISTORICAL"); 134 135 private final StoreFileInfo fileInfo; 136 137 // StoreFile.Reader 138 private volatile StoreFileReader initialReader; 139 private volatile InputStreamBlockDistribution initialReaderBlockDistribution = null; 140 141 // Block cache configuration and reference. 142 private final CacheConfig cacheConf; 143 private final BloomFilterMetrics metrics; 144 145 // Indicates if the file got compacted 146 private volatile boolean compactedAway = false; 147 148 // Indicates if the file contains historical cell versions. This is used when 149 // hbase.enable.historical.compaction.files is set to true. In that case, compactions 150 // can generate two files, one with the live cell versions and the other with the remaining 151 // (historical) cell versions. If isHistorical is true then the hfile is historical. 152 // Historical files are skipped for regular (not raw) scans for latest row versions. 153 // When hbase.enable.historical.compaction.files is false, isHistorical will be false 154 // for all files. This means all files will be treated as live files. Historical files are 155 // generated only when hbase.enable.historical.compaction.files is true. 156 private volatile boolean isHistorical = false; 157 158 // Keys for metadata stored in backing HFile. 159 // Set when we obtain a Reader. 160 private long sequenceid = -1; 161 162 // max of the MemstoreTS in the KV's in this store 163 // Set when we obtain a Reader. 164 private long maxMemstoreTS = -1; 165 166 // firstKey, lastkey and cellComparator will be set when openReader. 167 private Optional<ExtendedCell> firstKey; 168 169 private Optional<ExtendedCell> lastKey; 170 171 private CellComparator comparator; 172 173 public CacheConfig getCacheConf() { 174 return this.cacheConf; 175 } 176 177 @Override 178 public Optional<ExtendedCell> getFirstKey() { 179 return firstKey; 180 } 181 182 @Override 183 public Optional<ExtendedCell> getLastKey() { 184 return lastKey; 185 } 186 187 @Override 188 public CellComparator getComparator() { 189 return comparator; 190 } 191 192 @Override 193 public long getMaxMemStoreTS() { 194 return maxMemstoreTS; 195 } 196 197 // If true, this file was product of a major compaction. Its then set 198 // whenever you get a Reader. 199 private AtomicBoolean majorCompaction = null; 200 201 // If true, this file should not be included in minor compactions. 202 // It's set whenever you get a Reader. 203 private boolean excludeFromMinorCompaction = false; 204 205 // This file was product of these compacted store files 206 private final Set<String> compactedStoreFiles = new HashSet<>(); 207 208 /** 209 * Map of the metadata entries in the corresponding HFile. Populated when Reader is opened after 210 * which it is not modified again. 211 */ 212 private Map<byte[], byte[]> metadataMap; 213 214 /** 215 * Bloom filter type specified in column family configuration. Does not necessarily correspond to 216 * the Bloom filter type present in the HFile. 217 */ 218 private final BloomType cfBloomType; 219 220 private String keyNamespace; 221 222 private SystemKeyCache systemKeyCache; 223 224 private final ManagedKeyDataCache managedKeyDataCache; 225 226 /** 227 * Constructor, loads a reader and it's indices, etc. May allocate a substantial amount of ram 228 * depending on the underlying files (10-20MB?). Since this is used only in read path, key 229 * namespace is not needed. 230 * @param fs The current file system to use. 231 * @param p The path of the file. 232 * @param conf The current configuration. 233 * @param cacheConf The cache configuration and block cache reference. 234 * @param cfBloomType The bloom type to use for this store file as specified by column family 235 * configuration. This may or may not be the same as the Bloom filter type 236 * actually present in the HFile, because column family configuration might 237 * change. If this is {@link BloomType#NONE}, the existing Bloom filter is 238 * ignored. 239 * @param primaryReplica true if this is a store file for primary replica, otherwise false. 240 */ 241 public HStoreFile(FileSystem fs, Path p, Configuration conf, CacheConfig cacheConf, 242 BloomType cfBloomType, boolean primaryReplica, StoreFileTracker sft) throws IOException { 243 // Key management not yet implemented - always null 244 this(sft.getStoreFileInfo(p, primaryReplica), cfBloomType, cacheConf, null, null, null, null); 245 } 246 247 /** 248 * Constructor, loads a reader and it's indices, etc. May allocate a substantial amount of ram 249 * depending on the underlying files (10-20MB?). 250 * @param fileInfo The store file information. 251 * @param cfBloomType The bloom type to use for this store file as specified by column family 252 * configuration. This may or may not be the same as the Bloom filter type 253 * actually present in the HFile, because column family configuration might 254 * change. If this is {@link BloomType#NONE}, the existing Bloom filter is 255 * ignored. 256 * @param cacheConf The cache configuration and block cache reference. 257 */ 258 public HStoreFile(StoreFileInfo fileInfo, BloomType cfBloomType, CacheConfig cacheConf) 259 throws IOException { 260 // Key management not yet implemented - always null 261 this(fileInfo, cfBloomType, cacheConf, null, null, // keyNamespace - not yet implemented 262 null, null); 263 } 264 265 /** 266 * Constructor, loads a reader and it's indices, etc. May allocate a substantial amount of ram 267 * depending on the underlying files (10-20MB?). 268 * @param fileInfo The store file information. 269 * @param cfBloomType The bloom type to use for this store file as specified by column family 270 * configuration. This may or may not be the same as the Bloom filter type 271 * actually present in the HFile, because column family configuration might 272 * change. If this is {@link BloomType#NONE}, the existing Bloom filter is 273 * ignored. 274 * @param cacheConf The cache configuration and block cache reference. 275 * @param metrics Tracks bloom filter requests and results. May be null. 276 */ 277 public HStoreFile(StoreFileInfo fileInfo, BloomType cfBloomType, CacheConfig cacheConf, 278 BloomFilterMetrics metrics, String keyNamespace, SystemKeyCache systemKeyCache, 279 ManagedKeyDataCache managedKeyDataCache) { 280 this.fileInfo = fileInfo; 281 this.cacheConf = cacheConf; 282 this.metrics = metrics; 283 this.keyNamespace = keyNamespace != null ? keyNamespace : KEY_SPACE_GLOBAL; 284 this.systemKeyCache = systemKeyCache; 285 this.managedKeyDataCache = managedKeyDataCache; 286 if (BloomFilterFactory.isGeneralBloomEnabled(fileInfo.getConf())) { 287 this.cfBloomType = cfBloomType; 288 } else { 289 LOG.info("Ignoring bloom filter check for file " + this.getPath() + ": " + "cfBloomType=" 290 + cfBloomType + " (disabled in config)"); 291 this.cfBloomType = BloomType.NONE; 292 } 293 } 294 295 /** 296 * @return the StoreFile object associated to this StoreFile. null if the StoreFile is not a 297 * reference. 298 */ 299 public StoreFileInfo getFileInfo() { 300 return this.fileInfo; 301 } 302 303 @Override 304 public Path getPath() { 305 return this.fileInfo.getPath(); 306 } 307 308 @Override 309 public Path getEncodedPath() { 310 try { 311 return new Path(URLEncoder.encode(fileInfo.getPath().toString(), HConstants.UTF8_ENCODING)); 312 } catch (UnsupportedEncodingException ex) { 313 throw new RuntimeException("URLEncoder doesn't support UTF-8", ex); 314 } 315 } 316 317 @Override 318 public Path getQualifiedPath() { 319 FileSystem fs = fileInfo.getFileSystem(); 320 return this.fileInfo.getPath().makeQualified(fs.getUri(), fs.getWorkingDirectory()); 321 } 322 323 @Override 324 public boolean isReference() { 325 return this.fileInfo.isReference(); 326 } 327 328 @Override 329 public boolean isHFile() { 330 return StoreFileInfo.isHFile(this.fileInfo.getPath()); 331 } 332 333 @Override 334 public boolean isMajorCompactionResult() { 335 Preconditions.checkState(this.majorCompaction != null, "Major compation has not been set yet"); 336 return this.majorCompaction.get(); 337 } 338 339 @Override 340 public boolean excludeFromMinorCompaction() { 341 return this.excludeFromMinorCompaction; 342 } 343 344 @Override 345 public long getMaxSequenceId() { 346 return this.sequenceid; 347 } 348 349 @Override 350 public long getModificationTimestamp() throws IOException { 351 return fileInfo.getModificationTime(); 352 } 353 354 /** 355 * @param key to look up 356 * @return value associated with the metadata key 357 */ 358 public byte[] getMetadataValue(byte[] key) { 359 return metadataMap.get(key); 360 } 361 362 @Override 363 public boolean isBulkLoadResult() { 364 return StoreFileInfo.hasBulkloadSeqId(this.getPath()) 365 || (metadataMap != null && metadataMap.containsKey(BULKLOAD_TIME_KEY)); 366 } 367 368 public boolean isCompactedAway() { 369 return compactedAway; 370 } 371 372 public boolean isHistorical() { 373 return isHistorical; 374 } 375 376 public int getRefCount() { 377 return fileInfo.getRefCount(); 378 } 379 380 /** Returns true if the file is still used in reads */ 381 public boolean isReferencedInReads() { 382 int rc = fileInfo.getRefCount(); 383 assert rc >= 0; // we should not go negative. 384 return rc > 0; 385 } 386 387 @Override 388 public OptionalLong getBulkLoadTimestamp() { 389 byte[] bulkLoadTimestamp = metadataMap.get(BULKLOAD_TIME_KEY); 390 return bulkLoadTimestamp == null 391 ? OptionalLong.empty() 392 : OptionalLong.of(Bytes.toLong(bulkLoadTimestamp)); 393 } 394 395 /** 396 * @return the cached value of HDFS blocks distribution. The cached value is calculated when store 397 * file is opened. 398 */ 399 public HDFSBlocksDistribution getHDFSBlockDistribution() { 400 if (initialReaderBlockDistribution != null) { 401 return initialReaderBlockDistribution.getHDFSBlockDistribution(); 402 } else { 403 return this.fileInfo.getHDFSBlockDistribution(); 404 } 405 } 406 407 /** 408 * Opens reader on this store file. Called by Constructor. 409 * @see #closeStoreFile(boolean) 410 */ 411 private void open() throws IOException { 412 fileInfo.initHDFSBlocksDistribution(); 413 long readahead = fileInfo.isNoReadahead() ? 0L : -1L; 414 ReaderContext context = fileInfo.createReaderContext(false, readahead, ReaderType.PREAD, 415 keyNamespace, systemKeyCache, managedKeyDataCache); 416 fileInfo.initHFileInfo(context); 417 StoreFileReader reader = fileInfo.preStoreFileReaderOpen(context, cacheConf); 418 if (reader == null) { 419 reader = fileInfo.createReader(context, cacheConf); 420 fileInfo.getHFileInfo().initMetaAndIndex(reader.getHFileReader()); 421 } 422 this.initialReader = fileInfo.postStoreFileReaderOpen(context, cacheConf, reader); 423 424 if (InputStreamBlockDistribution.isEnabled(fileInfo.getConf())) { 425 boolean useHBaseChecksum = context.getInputStreamWrapper().shouldUseHBaseChecksum(); 426 FSDataInputStream stream = context.getInputStreamWrapper().getStream(useHBaseChecksum); 427 this.initialReaderBlockDistribution = new InputStreamBlockDistribution(stream, fileInfo); 428 } 429 430 // Load up indices and fileinfo. This also loads Bloom filter type. 431 metadataMap = Collections.unmodifiableMap(initialReader.loadFileInfo()); 432 433 // Read in our metadata. 434 byte[] b = metadataMap.get(MAX_SEQ_ID_KEY); 435 if (b != null) { 436 // By convention, if halfhfile, top half has a sequence number > bottom 437 // half. Thats why we add one in below. Its done for case the two halves 438 // are ever merged back together --rare. Without it, on open of store, 439 // since store files are distinguished by sequence id, the one half would 440 // subsume the other. 441 this.sequenceid = Bytes.toLong(b); 442 if (fileInfo.isTopReference()) { 443 this.sequenceid += 1; 444 } 445 } 446 447 if (isBulkLoadResult()) { 448 // For bulkloads, we have to parse the sequenceid from the path name 449 OptionalLong sequenceId = StoreFileInfo.getBulkloadSeqId(this.getPath()); 450 if (sequenceId.isPresent()) { 451 this.sequenceid = sequenceId.getAsLong(); 452 // Handle reference files as done above. 453 if (fileInfo.isTopReference()) { 454 this.sequenceid += 1; 455 } 456 } 457 458 // SKIP_RESET_SEQ_ID only works in bulk loaded file. 459 // In mob compaction, the hfile where the cells contain the path of a new mob file is bulk 460 // loaded to hbase, these cells have the same seqIds with the old ones. We do not want 461 // to reset new seqIds for them since this might make a mess of the visibility of cells that 462 // have the same row key but different seqIds. 463 boolean skipResetSeqId = isSkipResetSeqId(metadataMap.get(SKIP_RESET_SEQ_ID)); 464 if (skipResetSeqId) { 465 // increase the seqId when it is a bulk loaded file from mob compaction. 466 this.sequenceid += 1; 467 } 468 initialReader.setSkipResetSeqId(skipResetSeqId); 469 initialReader.setBulkLoaded(true); 470 } 471 initialReader.setSequenceID(this.sequenceid); 472 473 b = metadataMap.get(HFile.Writer.MAX_MEMSTORE_TS_KEY); 474 if (b != null) { 475 this.maxMemstoreTS = Bytes.toLong(b); 476 } 477 478 b = metadataMap.get(MAJOR_COMPACTION_KEY); 479 if (b != null) { 480 boolean mc = Bytes.toBoolean(b); 481 if (this.majorCompaction == null) { 482 this.majorCompaction = new AtomicBoolean(mc); 483 } else { 484 this.majorCompaction.set(mc); 485 } 486 } else { 487 // Presume it is not major compacted if it doesn't explicity say so 488 // HFileOutputFormat explicitly sets the major compacted key. 489 this.majorCompaction = new AtomicBoolean(false); 490 } 491 492 b = metadataMap.get(EXCLUDE_FROM_MINOR_COMPACTION_KEY); 493 this.excludeFromMinorCompaction = (b != null && Bytes.toBoolean(b)); 494 495 b = metadataMap.get(HISTORICAL_KEY); 496 if (b != null) { 497 isHistorical = Bytes.toBoolean(b); 498 } 499 BloomType hfileBloomType = initialReader.getBloomFilterType(); 500 if (cfBloomType != BloomType.NONE) { 501 initialReader.loadBloomfilter(BlockType.GENERAL_BLOOM_META, metrics); 502 if (hfileBloomType != cfBloomType) { 503 LOG.debug("HFile Bloom filter type for " + initialReader.getHFileReader().getName() + ": " 504 + hfileBloomType + ", but " + cfBloomType + " specified in column family " 505 + "configuration"); 506 } 507 } else if (hfileBloomType != BloomType.NONE) { 508 LOG.info( 509 "Bloom filter turned off by CF config for " + initialReader.getHFileReader().getName()); 510 } 511 512 // load delete family bloom filter 513 initialReader.loadBloomfilter(BlockType.DELETE_FAMILY_BLOOM_META, metrics); 514 515 try { 516 byte[] data = metadataMap.get(TIMERANGE_KEY); 517 initialReader.timeRange = 518 data == null ? null : TimeRangeTracker.parseFrom(data).toTimeRange(); 519 } catch (IllegalArgumentException e) { 520 LOG.error("Error reading timestamp range data from meta -- " + "proceeding without", e); 521 this.initialReader.timeRange = null; 522 } 523 524 try { 525 byte[] data = metadataMap.get(COMPACTION_EVENT_KEY); 526 this.compactedStoreFiles.addAll(ProtobufUtil.toCompactedStoreFiles(data)); 527 } catch (IOException e) { 528 LOG.error("Error reading compacted storefiles from meta data", e); 529 } 530 531 // initialize so we can reuse them after reader closed. 532 firstKey = initialReader.getFirstKey(); 533 lastKey = initialReader.getLastKey(); 534 comparator = initialReader.getComparator(); 535 } 536 537 /** 538 * Initialize the reader used for pread. 539 */ 540 public void initReader() throws IOException { 541 if (initialReader == null) { 542 synchronized (this) { 543 if (initialReader == null) { 544 try { 545 open(); 546 } catch (Exception e) { 547 try { 548 boolean evictOnClose = cacheConf != null ? cacheConf.shouldEvictOnClose() : true; 549 this.closeStoreFile(evictOnClose); 550 } catch (IOException ee) { 551 LOG.warn("failed to close reader", ee); 552 } 553 throw e; 554 } 555 } 556 } 557 } 558 } 559 560 private StoreFileReader createStreamReader(boolean canUseDropBehind) throws IOException { 561 initReader(); 562 final boolean doDropBehind = canUseDropBehind && cacheConf.shouldDropBehindCompaction(); 563 ReaderContext context = fileInfo.createReaderContext(doDropBehind, -1, ReaderType.STREAM, 564 keyNamespace, systemKeyCache, managedKeyDataCache); 565 StoreFileReader reader = fileInfo.preStoreFileReaderOpen(context, cacheConf); 566 if (reader == null) { 567 reader = fileInfo.createReader(context, cacheConf); 568 // steam reader need copy stuffs from pread reader 569 reader.copyFields(initialReader); 570 } 571 return fileInfo.postStoreFileReaderOpen(context, cacheConf, reader); 572 } 573 574 /** 575 * Get a scanner which uses pread. 576 * <p> 577 * Must be called after initReader. 578 */ 579 public StoreFileScanner getPreadScanner(boolean cacheBlocks, long readPt, long scannerOrder, 580 boolean canOptimizeForNonNullColumn) { 581 return getReader().getStoreFileScanner(cacheBlocks, true, false, readPt, scannerOrder, 582 canOptimizeForNonNullColumn); 583 } 584 585 /** 586 * Get a scanner which uses streaming read. 587 * <p> 588 * Must be called after initReader. 589 */ 590 public StoreFileScanner getStreamScanner(boolean canUseDropBehind, boolean cacheBlocks, 591 boolean isCompaction, long readPt, long scannerOrder, boolean canOptimizeForNonNullColumn) 592 throws IOException { 593 return createStreamReader(canUseDropBehind).getStoreFileScanner(cacheBlocks, false, 594 isCompaction, readPt, scannerOrder, canOptimizeForNonNullColumn); 595 } 596 597 /** 598 * @return Current reader. Must call initReader first else returns null. 599 * @see #initReader() 600 */ 601 public StoreFileReader getReader() { 602 return this.initialReader; 603 } 604 605 /** 606 * @param evictOnClose whether to evict blocks belonging to this file 607 */ 608 public synchronized void closeStoreFile(boolean evictOnClose) throws IOException { 609 if (this.initialReader != null) { 610 this.initialReader.close(evictOnClose); 611 this.initialReader = null; 612 } 613 } 614 615 /** 616 * Delete this file 617 */ 618 public void deleteStoreFile() throws IOException { 619 boolean evictOnClose = cacheConf != null ? cacheConf.shouldEvictOnClose() : true; 620 closeStoreFile(evictOnClose); 621 this.fileInfo.getFileSystem().delete(getPath(), true); 622 } 623 624 public void markCompactedAway() { 625 this.compactedAway = true; 626 } 627 628 @Override 629 public String toString() { 630 return this.fileInfo.toString(); 631 } 632 633 @Override 634 public String toStringDetailed() { 635 StringBuilder sb = new StringBuilder(); 636 sb.append(this.getPath().toString()); 637 sb.append(", isReference=").append(isReference()); 638 sb.append(", isBulkLoadResult=").append(isBulkLoadResult()); 639 if (isBulkLoadResult()) { 640 sb.append(", bulkLoadTS="); 641 OptionalLong bulkLoadTS = getBulkLoadTimestamp(); 642 if (bulkLoadTS.isPresent()) { 643 sb.append(bulkLoadTS.getAsLong()); 644 } else { 645 sb.append("NotPresent"); 646 } 647 } else { 648 sb.append(", seqid=").append(getMaxSequenceId()); 649 } 650 sb.append(", majorCompaction=").append(isMajorCompactionResult()); 651 652 return sb.toString(); 653 } 654 655 /** 656 * Gets whether to skip resetting the sequence id for cells. 657 * @param skipResetSeqId The byte array of boolean. 658 * @return Whether to skip resetting the sequence id. 659 */ 660 private boolean isSkipResetSeqId(byte[] skipResetSeqId) { 661 if (skipResetSeqId != null && skipResetSeqId.length == 1) { 662 return Bytes.toBoolean(skipResetSeqId); 663 } 664 return false; 665 } 666 667 @Override 668 public OptionalLong getMinimumTimestamp() { 669 TimeRange tr = getReader().timeRange; 670 return tr != null ? OptionalLong.of(tr.getMin()) : OptionalLong.empty(); 671 } 672 673 @Override 674 public OptionalLong getMaximumTimestamp() { 675 TimeRange tr = getReader().timeRange; 676 return tr != null ? OptionalLong.of(tr.getMax()) : OptionalLong.empty(); 677 } 678 679 Set<String> getCompactedStoreFiles() { 680 return Collections.unmodifiableSet(this.compactedStoreFiles); 681 } 682 683 long increaseRefCount() { 684 return this.fileInfo.increaseRefCount(); 685 } 686 687 long decreaseRefCount() { 688 return this.fileInfo.decreaseRefCount(); 689 } 690 691 static void increaseStoreFilesRefeCount(Collection<HStoreFile> storeFiles) { 692 if (CollectionUtils.isEmpty(storeFiles)) { 693 return; 694 } 695 storeFiles.forEach(HStoreFile::increaseRefCount); 696 } 697 698 static void decreaseStoreFilesRefeCount(Collection<HStoreFile> storeFiles) { 699 if (CollectionUtils.isEmpty(storeFiles)) { 700 return; 701 } 702 storeFiles.forEach(HStoreFile::decreaseRefCount); 703 } 704}