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 java.io.FileNotFoundException; 021import java.io.IOException; 022import java.util.OptionalLong; 023import java.util.concurrent.atomic.AtomicInteger; 024import java.util.regex.Matcher; 025import java.util.regex.Pattern; 026import org.apache.hadoop.conf.Configurable; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.fs.FileStatus; 029import org.apache.hadoop.fs.FileSystem; 030import org.apache.hadoop.fs.Path; 031import org.apache.hadoop.hbase.HDFSBlocksDistribution; 032import org.apache.hadoop.hbase.io.FSDataInputStreamWrapper; 033import org.apache.hadoop.hbase.io.HFileLink; 034import org.apache.hadoop.hbase.io.HalfStoreFileReader; 035import org.apache.hadoop.hbase.io.Reference; 036import org.apache.hadoop.hbase.io.hfile.CacheConfig; 037import org.apache.hadoop.hbase.io.hfile.HFileInfo; 038import org.apache.hadoop.hbase.io.hfile.ReaderContext; 039import org.apache.hadoop.hbase.io.hfile.ReaderContext.ReaderType; 040import org.apache.hadoop.hbase.io.hfile.ReaderContextBuilder; 041import org.apache.hadoop.hbase.mob.MobUtils; 042import org.apache.hadoop.hbase.util.FSUtils; 043import org.apache.hadoop.hbase.util.Pair; 044import org.apache.yetus.audience.InterfaceAudience; 045import org.slf4j.Logger; 046import org.slf4j.LoggerFactory; 047 048/** 049 * Describe a StoreFile (hfile, reference, link) 050 */ 051@InterfaceAudience.Private 052public class StoreFileInfo implements Configurable { 053 private static final Logger LOG = LoggerFactory.getLogger(StoreFileInfo.class); 054 055 /** 056 * A non-capture group, for hfiles, so that this can be embedded. HFiles are uuid ([0-9a-z]+). 057 * Bulk loaded hfiles has (_SeqId_[0-9]+_) has suffix. The mob del file has (_del) as suffix. 058 */ 059 public static final String HFILE_NAME_REGEX = "[0-9a-f]+(?:(?:_SeqId_[0-9]+_)|(?:_del))?"; 060 061 /** Regex that will work for hfiles */ 062 private static final Pattern HFILE_NAME_PATTERN = Pattern.compile("^(" + HFILE_NAME_REGEX + ")"); 063 064 /** 065 * Regex that will work for straight reference names ({@code <hfile>.<parentEncRegion>}) and 066 * hfilelink reference names ({@code 067 * 068 <table> 069 * =<region>-<hfile>.<parentEncRegion>}) If reference, then the regex has more than just one 070 * group. Group 1, hfile/hfilelink pattern, is this file's id. Group 2 '(.+)' is the reference's 071 * parent region name. 072 */ 073 private static final Pattern REF_NAME_PATTERN = 074 Pattern.compile(String.format("^(%s|%s)\\.(.+)$", HFILE_NAME_REGEX, HFileLink.LINK_NAME_REGEX)); 075 076 public static final String STORE_FILE_READER_NO_READAHEAD = "hbase.store.reader.no-readahead"; 077 public static final boolean DEFAULT_STORE_FILE_READER_NO_READAHEAD = true; 078 079 // Configuration 080 private Configuration conf; 081 082 // FileSystem handle 083 private final FileSystem fs; 084 085 // HDFS blocks distribution information 086 private HDFSBlocksDistribution hdfsBlocksDistribution = null; 087 088 private HFileInfo hfileInfo; 089 090 // If this storefile references another, this is the reference instance. 091 private final Reference reference; 092 093 // If this storefile is a link to another, this is the link instance. 094 private final HFileLink link; 095 096 private final Path initialPath; 097 098 private RegionCoprocessorHost coprocessorHost; 099 100 // timestamp on when the file was created, is 0 and ignored for reference or link files 101 private long createdTimestamp; 102 103 private long size; 104 105 private final boolean primaryReplica; 106 107 private final boolean noReadahead; 108 109 // Counter that is incremented every time a scanner is created on the 110 // store file. It is decremented when the scan on the store file is 111 // done. 112 private final AtomicInteger refCount = new AtomicInteger(0); 113 114 /** 115 * Create a Store File Info 116 * @param conf the {@link Configuration} to use 117 * @param fs The current file system to use. 118 * @param initialPath The {@link Path} of the file 119 * @param primaryReplica true if this is a store file for primary replica, otherwise false. 120 */ 121 public StoreFileInfo(final Configuration conf, final FileSystem fs, final Path initialPath, 122 final boolean primaryReplica) throws IOException { 123 this(conf, fs, null, initialPath, primaryReplica); 124 } 125 126 private StoreFileInfo(final Configuration conf, final FileSystem fs, final FileStatus fileStatus, 127 final Path initialPath, final boolean primaryReplica) throws IOException { 128 assert fs != null; 129 assert initialPath != null; 130 assert conf != null; 131 132 this.fs = fs; 133 this.conf = conf; 134 this.initialPath = fs.makeQualified(initialPath); 135 this.primaryReplica = primaryReplica; 136 this.noReadahead = 137 this.conf.getBoolean(STORE_FILE_READER_NO_READAHEAD, DEFAULT_STORE_FILE_READER_NO_READAHEAD); 138 Path p = initialPath; 139 if (HFileLink.isHFileLink(p)) { 140 // HFileLink 141 this.reference = null; 142 this.link = HFileLink.buildFromHFileLinkPattern(conf, p); 143 LOG.trace("{} is a link", p); 144 } else if (isReference(p)) { 145 this.reference = Reference.read(fs, p); 146 Path referencePath = getReferredToFile(p); 147 if (HFileLink.isHFileLink(referencePath)) { 148 // HFileLink Reference 149 this.link = HFileLink.buildFromHFileLinkPattern(conf, referencePath); 150 } else { 151 // Reference 152 this.link = null; 153 } 154 LOG.trace("{} is a {} reference to {}", p, reference.getFileRegion(), referencePath); 155 } else if (isHFile(p) || isMobFile(p) || isMobRefFile(p)) { 156 // HFile 157 if (fileStatus != null) { 158 this.createdTimestamp = fileStatus.getModificationTime(); 159 this.size = fileStatus.getLen(); 160 } else { 161 FileStatus fStatus = fs.getFileStatus(initialPath); 162 this.createdTimestamp = fStatus.getModificationTime(); 163 this.size = fStatus.getLen(); 164 } 165 this.reference = null; 166 this.link = null; 167 } else { 168 throw new IOException("path=" + p + " doesn't look like a valid StoreFile"); 169 } 170 } 171 172 /** 173 * Create a Store File Info 174 * @param conf the {@link Configuration} to use 175 * @param fs The current file system to use. 176 * @param fileStatus The {@link FileStatus} of the file 177 */ 178 public StoreFileInfo(final Configuration conf, final FileSystem fs, final FileStatus fileStatus) 179 throws IOException { 180 this(conf, fs, fileStatus, fileStatus.getPath(), true); 181 } 182 183 /** 184 * Create a Store File Info from an HFileLink 185 * @param conf The {@link Configuration} to use 186 * @param fs The current file system to use 187 * @param fileStatus The {@link FileStatus} of the file 188 */ 189 public StoreFileInfo(final Configuration conf, final FileSystem fs, final FileStatus fileStatus, 190 final HFileLink link) { 191 this(conf, fs, fileStatus, null, link); 192 } 193 194 /** 195 * Create a Store File Info from an HFileLink 196 * @param conf The {@link Configuration} to use 197 * @param fs The current file system to use 198 * @param fileStatus The {@link FileStatus} of the file 199 * @param reference The reference instance 200 */ 201 public StoreFileInfo(final Configuration conf, final FileSystem fs, final FileStatus fileStatus, 202 final Reference reference) { 203 this(conf, fs, fileStatus, reference, null); 204 } 205 206 /** 207 * Create a Store File Info from an HFileLink and a Reference 208 * @param conf The {@link Configuration} to use 209 * @param fs The current file system to use 210 * @param fileStatus The {@link FileStatus} of the file 211 * @param reference The reference instance 212 * @param link The link instance 213 */ 214 public StoreFileInfo(final Configuration conf, final FileSystem fs, final FileStatus fileStatus, 215 final Reference reference, final HFileLink link) { 216 this.fs = fs; 217 this.conf = conf; 218 this.primaryReplica = false; 219 this.initialPath = (fileStatus == null) ? null : fileStatus.getPath(); 220 this.createdTimestamp = (fileStatus == null) ? 0 : fileStatus.getModificationTime(); 221 this.reference = reference; 222 this.link = link; 223 this.noReadahead = 224 this.conf.getBoolean(STORE_FILE_READER_NO_READAHEAD, DEFAULT_STORE_FILE_READER_NO_READAHEAD); 225 } 226 227 @Override 228 public Configuration getConf() { 229 return conf; 230 } 231 232 @Override 233 public void setConf(Configuration conf) { 234 this.conf = conf; 235 } 236 237 /** 238 * Size of the Hfile 239 */ 240 public long getSize() { 241 return size; 242 } 243 244 /** 245 * Sets the region coprocessor env. 246 */ 247 public void setRegionCoprocessorHost(RegionCoprocessorHost coprocessorHost) { 248 this.coprocessorHost = coprocessorHost; 249 } 250 251 /* 252 * @return the Reference object associated to this StoreFileInfo. null if the StoreFile is not a 253 * reference. 254 */ 255 public Reference getReference() { 256 return this.reference; 257 } 258 259 /** Returns True if the store file is a Reference */ 260 public boolean isReference() { 261 return this.reference != null; 262 } 263 264 /** Returns True if the store file is a top Reference */ 265 public boolean isTopReference() { 266 return this.reference != null && Reference.isTopFileRegion(this.reference.getFileRegion()); 267 } 268 269 /** Returns True if the store file is a link */ 270 public boolean isLink() { 271 return this.link != null && this.reference == null; 272 } 273 274 /** Returns the HDFS block distribution */ 275 public HDFSBlocksDistribution getHDFSBlockDistribution() { 276 return this.hdfsBlocksDistribution; 277 } 278 279 public StoreFileReader createReader(ReaderContext context, CacheConfig cacheConf) 280 throws IOException { 281 StoreFileReader reader = null; 282 if (this.reference != null) { 283 reader = new HalfStoreFileReader(context, hfileInfo, cacheConf, reference, this, conf); 284 } else { 285 reader = new StoreFileReader(context, hfileInfo, cacheConf, this, conf); 286 } 287 return reader; 288 } 289 290 ReaderContext createReaderContext(boolean doDropBehind, long readahead, ReaderType type) 291 throws IOException { 292 FSDataInputStreamWrapper in; 293 FileStatus status; 294 if (this.link != null) { 295 // HFileLink 296 in = new FSDataInputStreamWrapper(fs, this.link, doDropBehind, readahead); 297 status = this.link.getFileStatus(fs); 298 } else if (this.reference != null) { 299 // HFile Reference 300 Path referencePath = getReferredToFile(this.getPath()); 301 try { 302 in = new FSDataInputStreamWrapper(fs, referencePath, doDropBehind, readahead); 303 } catch (FileNotFoundException fnfe) { 304 // Intercept the exception so can insert more info about the Reference; otherwise 305 // exception just complains about some random file -- operator doesn't realize it 306 // other end of a Reference 307 FileNotFoundException newFnfe = new FileNotFoundException(toString()); 308 newFnfe.initCause(fnfe); 309 throw newFnfe; 310 } 311 status = fs.getFileStatus(referencePath); 312 } else { 313 in = new FSDataInputStreamWrapper(fs, this.getPath(), doDropBehind, readahead); 314 status = fs.getFileStatus(initialPath); 315 } 316 long length = status.getLen(); 317 ReaderContextBuilder contextBuilder = 318 new ReaderContextBuilder().withInputStreamWrapper(in).withFileSize(length) 319 .withPrimaryReplicaReader(this.primaryReplica).withReaderType(type).withFileSystem(fs); 320 if (this.reference != null) { 321 contextBuilder.withFilePath(this.getPath()); 322 } else { 323 contextBuilder.withFilePath(status.getPath()); 324 } 325 return contextBuilder.build(); 326 } 327 328 /** 329 * Compute the HDFS Block Distribution for this StoreFile 330 */ 331 public HDFSBlocksDistribution computeHDFSBlocksDistribution(final FileSystem fs) 332 throws IOException { 333 // guard against the case where we get the FileStatus from link, but by the time we 334 // call compute the file is moved again 335 if (this.link != null) { 336 FileNotFoundException exToThrow = null; 337 for (int i = 0; i < this.link.getLocations().length; i++) { 338 try { 339 return computeHDFSBlocksDistributionInternal(fs); 340 } catch (FileNotFoundException ex) { 341 // try the other location 342 exToThrow = ex; 343 } 344 } 345 throw exToThrow; 346 } else { 347 return computeHDFSBlocksDistributionInternal(fs); 348 } 349 } 350 351 private HDFSBlocksDistribution computeHDFSBlocksDistributionInternal(final FileSystem fs) 352 throws IOException { 353 FileStatus status = getReferencedFileStatus(fs); 354 if (this.reference != null) { 355 return computeRefFileHDFSBlockDistribution(fs, reference, status); 356 } else { 357 return FSUtils.computeHDFSBlocksDistribution(fs, status, 0, status.getLen()); 358 } 359 } 360 361 /** 362 * Get the {@link FileStatus} of the file referenced by this StoreFileInfo 363 * @param fs The current file system to use. 364 * @return The {@link FileStatus} of the file referenced by this StoreFileInfo 365 */ 366 public FileStatus getReferencedFileStatus(final FileSystem fs) throws IOException { 367 FileStatus status; 368 if (this.reference != null) { 369 if (this.link != null) { 370 FileNotFoundException exToThrow = null; 371 for (int i = 0; i < this.link.getLocations().length; i++) { 372 // HFileLink Reference 373 try { 374 return link.getFileStatus(fs); 375 } catch (FileNotFoundException ex) { 376 // try the other location 377 exToThrow = ex; 378 } 379 } 380 throw exToThrow; 381 } else { 382 // HFile Reference 383 Path referencePath = getReferredToFile(this.getPath()); 384 status = fs.getFileStatus(referencePath); 385 } 386 } else { 387 if (this.link != null) { 388 FileNotFoundException exToThrow = null; 389 for (int i = 0; i < this.link.getLocations().length; i++) { 390 // HFileLink 391 try { 392 return link.getFileStatus(fs); 393 } catch (FileNotFoundException ex) { 394 // try the other location 395 exToThrow = ex; 396 } 397 } 398 throw exToThrow; 399 } else { 400 status = fs.getFileStatus(initialPath); 401 } 402 } 403 return status; 404 } 405 406 /** Returns The {@link Path} of the file */ 407 public Path getPath() { 408 return initialPath; 409 } 410 411 /** Returns The {@link FileStatus} of the file */ 412 public FileStatus getFileStatus() throws IOException { 413 return getReferencedFileStatus(fs); 414 } 415 416 /** Returns Get the modification time of the file. */ 417 public long getModificationTime() throws IOException { 418 return getFileStatus().getModificationTime(); 419 } 420 421 @Override 422 public String toString() { 423 return this.getPath() 424 + (isReference() ? "->" + getReferredToFile(this.getPath()) + "-" + reference : ""); 425 } 426 427 /** 428 * Cells in a bulkloaded file don't have a sequenceId since they don't go through memstore. When a 429 * bulkload file is committed, the current memstore ts is stamped onto the file name as the 430 * sequenceId of the file. At read time, the sequenceId is copied onto all of the cells returned 431 * so that they can be properly sorted relative to other cells in other files. Further, when 432 * opening multiple files for scan, the sequence id is used to ensusre that the bulkload file's 433 * scanner is porperly sorted amongst the other scanners. Non-bulkloaded files get their 434 * sequenceId from the MAX_MEMSTORE_TS_KEY since those go through the memstore and have true 435 * sequenceIds. 436 */ 437 private static final String SEQ_ID_MARKER = "_SeqId_"; 438 private static final int SEQ_ID_MARKER_LENGTH = SEQ_ID_MARKER.length(); 439 440 /** 441 * @see #SEQ_ID_MARKER 442 * @return True if the file name looks like a bulkloaded file, based on the presence of the SeqId 443 * marker added to those files. 444 */ 445 public static boolean hasBulkloadSeqId(final Path path) { 446 String fileName = path.getName(); 447 return fileName.contains(SEQ_ID_MARKER); 448 } 449 450 /** 451 * @see #SEQ_ID_MARKER 452 * @return If the path is a properly named bulkloaded file, returns the sequence id stamped at the 453 * end of the file name. 454 */ 455 public static OptionalLong getBulkloadSeqId(final Path path) { 456 String fileName = path.getName(); 457 int startPos = fileName.indexOf(SEQ_ID_MARKER); 458 if (startPos != -1) { 459 String strVal = fileName.substring(startPos + SEQ_ID_MARKER_LENGTH, 460 fileName.indexOf('_', startPos + SEQ_ID_MARKER_LENGTH)); 461 return OptionalLong.of(Long.parseLong(strVal)); 462 } 463 return OptionalLong.empty(); 464 } 465 466 /** 467 * @see #SEQ_ID_MARKER 468 * @return A string value for appending to the end of a bulkloaded file name, containing the 469 * properly formatted SeqId marker. 470 */ 471 public static String formatBulkloadSeqId(long seqId) { 472 return SEQ_ID_MARKER + seqId + "_"; 473 } 474 475 /** 476 * @param path Path to check. 477 * @return True if the path has format of a HFile. 478 */ 479 public static boolean isHFile(final Path path) { 480 return isHFile(path.getName()); 481 } 482 483 public static boolean isHFile(final String fileName) { 484 Matcher m = HFILE_NAME_PATTERN.matcher(fileName); 485 return m.matches() && m.groupCount() > 0; 486 } 487 488 /** 489 * Checks if the file is a MOB file 490 * @param path path to a file 491 * @return true, if - yes, false otherwise 492 */ 493 public static boolean isMobFile(final Path path) { 494 String fileName = path.getName(); 495 String[] parts = fileName.split(MobUtils.SEP); 496 if (parts.length != 2) { 497 return false; 498 } 499 Matcher m = HFILE_NAME_PATTERN.matcher(parts[0]); 500 Matcher mm = HFILE_NAME_PATTERN.matcher(parts[1]); 501 return m.matches() && mm.matches(); 502 } 503 504 /** 505 * Checks if the file is a MOB reference file, created by snapshot 506 * @param path path to a file 507 * @return true, if - yes, false otherwise 508 */ 509 public static boolean isMobRefFile(final Path path) { 510 String fileName = path.getName(); 511 int lastIndex = fileName.lastIndexOf(MobUtils.SEP); 512 if (lastIndex < 0) { 513 return false; 514 } 515 String[] parts = new String[2]; 516 parts[0] = fileName.substring(0, lastIndex); 517 parts[1] = fileName.substring(lastIndex + 1); 518 String name = parts[0] + "." + parts[1]; 519 Matcher m = REF_NAME_PATTERN.matcher(name); 520 return m.matches() && m.groupCount() > 1; 521 } 522 523 /** 524 * @param path Path to check. 525 * @return True if the path has format of a HStoreFile reference. 526 */ 527 public static boolean isReference(final Path path) { 528 return isReference(path.getName()); 529 } 530 531 /** 532 * @param name file name to check. 533 * @return True if the path has format of a HStoreFile reference. 534 */ 535 public static boolean isReference(final String name) { 536 Matcher m = REF_NAME_PATTERN.matcher(name); 537 return m.matches() && m.groupCount() > 1; 538 } 539 540 /** Returns timestamp when this file was created (as returned by filesystem) */ 541 public long getCreatedTimestamp() { 542 return createdTimestamp; 543 } 544 545 /* 546 * Return path to the file referred to by a Reference. Presumes a directory hierarchy of 547 * <code>${hbase.rootdir}/data/${namespace}/tablename/regionname/familyname</code>. 548 * @param p Path to a Reference file. 549 * @return Calculated path to parent region file. 550 * @throws IllegalArgumentException when path regex fails to match. 551 */ 552 public static Path getReferredToFile(final Path p) { 553 Matcher m = REF_NAME_PATTERN.matcher(p.getName()); 554 if (m == null || !m.matches()) { 555 LOG.warn("Failed match of store file name {}", p.toString()); 556 throw new IllegalArgumentException("Failed match of store file name " + p.toString()); 557 } 558 559 // Other region name is suffix on the passed Reference file name 560 String otherRegion = m.group(2); 561 // Tabledir is up two directories from where Reference was written. 562 Path tableDir = p.getParent().getParent().getParent(); 563 String nameStrippedOfSuffix = m.group(1); 564 LOG.trace("reference {} to region={} hfile={}", p, otherRegion, nameStrippedOfSuffix); 565 566 // Build up new path with the referenced region in place of our current 567 // region in the reference path. Also strip regionname suffix from name. 568 return new Path(new Path(new Path(tableDir, otherRegion), p.getParent().getName()), 569 nameStrippedOfSuffix); 570 } 571 572 /* 573 * Return region and file name referred to by a Reference. 574 * @param referenceFile HFile name which is a Reference. 575 * @return Calculated referenced region and file name. 576 * @throws IllegalArgumentException when referenceFile regex fails to match. 577 */ 578 public static Pair<String, String> getReferredToRegionAndFile(final String referenceFile) { 579 Matcher m = REF_NAME_PATTERN.matcher(referenceFile); 580 if (m == null || !m.matches()) { 581 LOG.warn("Failed match of store file name {}", referenceFile); 582 throw new IllegalArgumentException("Failed match of store file name " + referenceFile); 583 } 584 String referencedRegion = m.group(2); 585 String referencedFile = m.group(1); 586 LOG.trace("reference {} to region={} file={}", referenceFile, referencedRegion, referencedFile); 587 return new Pair<>(referencedRegion, referencedFile); 588 } 589 590 /** 591 * Validate the store file name. 592 * @param fileName name of the file to validate 593 * @return <tt>true</tt> if the file could be a valid store file, <tt>false</tt> otherwise 594 */ 595 public static boolean validateStoreFileName(final String fileName) { 596 if (HFileLink.isHFileLink(fileName) || isReference(fileName)) return (true); 597 return !fileName.contains("-"); 598 } 599 600 /** 601 * Return if the specified file is a valid store file or not. 602 * @param fileStatus The {@link FileStatus} of the file 603 * @return <tt>true</tt> if the file is valid 604 */ 605 public static boolean isValid(final FileStatus fileStatus) throws IOException { 606 final Path p = fileStatus.getPath(); 607 608 if (fileStatus.isDirectory()) return false; 609 610 // Check for empty hfile. Should never be the case but can happen 611 // after data loss in hdfs for whatever reason (upgrade, etc.): HBASE-646 612 // NOTE: that the HFileLink is just a name, so it's an empty file. 613 if (!HFileLink.isHFileLink(p) && fileStatus.getLen() <= 0) { 614 LOG.warn("Skipping {} because it is empty. HBASE-646 DATA LOSS?", p); 615 return false; 616 } 617 618 return validateStoreFileName(p.getName()); 619 } 620 621 /** 622 * helper function to compute HDFS blocks distribution of a given reference file.For reference 623 * file, we don't compute the exact value. We use some estimate instead given it might be good 624 * enough. we assume bottom part takes the first half of reference file, top part takes the second 625 * half of the reference file. This is just estimate, given midkey ofregion != midkey of HFile, 626 * also the number and size of keys vary. If this estimate isn't good enough, we can improve it 627 * later. 628 * @param fs The FileSystem 629 * @param reference The reference 630 * @param status The reference FileStatus 631 * @return HDFS blocks distribution 632 */ 633 private static HDFSBlocksDistribution computeRefFileHDFSBlockDistribution(final FileSystem fs, 634 final Reference reference, final FileStatus status) throws IOException { 635 if (status == null) { 636 return null; 637 } 638 639 long start = 0; 640 long length = 0; 641 642 if (Reference.isTopFileRegion(reference.getFileRegion())) { 643 start = status.getLen() / 2; 644 length = status.getLen() - status.getLen() / 2; 645 } else { 646 start = 0; 647 length = status.getLen() / 2; 648 } 649 return FSUtils.computeHDFSBlocksDistribution(fs, status, start, length); 650 } 651 652 @Override 653 public boolean equals(Object that) { 654 if (this == that) { 655 return true; 656 } 657 if (that == null) { 658 return false; 659 } 660 661 if (!(that instanceof StoreFileInfo)) { 662 return false; 663 } 664 665 StoreFileInfo o = (StoreFileInfo) that; 666 if (initialPath != null && o.initialPath == null) return false; 667 if (initialPath == null && o.initialPath != null) return false; 668 if (initialPath != o.initialPath && initialPath != null && !initialPath.equals(o.initialPath)) 669 return false; 670 671 if (reference != null && o.reference == null) return false; 672 if (reference == null && o.reference != null) return false; 673 if (reference != o.reference && reference != null && !reference.equals(o.reference)) 674 return false; 675 676 if (link != null && o.link == null) { 677 return false; 678 } 679 if (link == null && o.link != null) { 680 return false; 681 } 682 if (link != o.link && link != null && !link.equals(o.link)) { 683 return false; 684 } 685 686 return true; 687 }; 688 689 @Override 690 public int hashCode() { 691 int hash = 17; 692 hash = hash * 31 + ((reference == null) ? 0 : reference.hashCode()); 693 hash = hash * 31 + ((initialPath == null) ? 0 : initialPath.hashCode()); 694 hash = hash * 31 + ((link == null) ? 0 : link.hashCode()); 695 return hash; 696 } 697 698 /** 699 * Return the active file name that contains the real data. 700 * <p> 701 * For referenced hfile, we will return the name of the reference file as it will be used to 702 * construct the StoreFileReader. And for linked hfile, we will return the name of the file being 703 * linked. 704 */ 705 public String getActiveFileName() { 706 if (reference != null || link == null) { 707 return initialPath.getName(); 708 } else { 709 return HFileLink.getReferencedHFileName(initialPath.getName()); 710 } 711 } 712 713 FileSystem getFileSystem() { 714 return this.fs; 715 } 716 717 boolean isNoReadahead() { 718 return this.noReadahead; 719 } 720 721 public HFileInfo getHFileInfo() { 722 return hfileInfo; 723 } 724 725 void initHDFSBlocksDistribution() throws IOException { 726 hdfsBlocksDistribution = computeHDFSBlocksDistribution(fs); 727 } 728 729 StoreFileReader preStoreFileReaderOpen(ReaderContext context, CacheConfig cacheConf) 730 throws IOException { 731 StoreFileReader reader = null; 732 if (this.coprocessorHost != null) { 733 reader = this.coprocessorHost.preStoreFileReaderOpen(fs, this.getPath(), 734 context.getInputStreamWrapper(), context.getFileSize(), cacheConf, reference); 735 } 736 return reader; 737 } 738 739 StoreFileReader postStoreFileReaderOpen(ReaderContext context, CacheConfig cacheConf, 740 StoreFileReader reader) throws IOException { 741 StoreFileReader res = reader; 742 if (this.coprocessorHost != null) { 743 res = this.coprocessorHost.postStoreFileReaderOpen(fs, this.getPath(), 744 context.getInputStreamWrapper(), context.getFileSize(), cacheConf, reference, reader); 745 } 746 return res; 747 } 748 749 public void initHFileInfo(ReaderContext context) throws IOException { 750 this.hfileInfo = new HFileInfo(context, conf); 751 } 752 753 int getRefCount() { 754 return this.refCount.get(); 755 } 756 757 int increaseRefCount() { 758 return this.refCount.incrementAndGet(); 759 } 760 761 int decreaseRefCount() { 762 return this.refCount.decrementAndGet(); 763 } 764 765}