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