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