2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package org
.apache
.hadoop
.hbase
.io
;
21 import java
.io
.IOException
;
22 import java
.util
.regex
.Matcher
;
23 import java
.util
.regex
.Pattern
;
25 import org
.apache
.hadoop
.conf
.Configuration
;
26 import org
.apache
.hadoop
.fs
.FileSystem
;
27 import org
.apache
.hadoop
.fs
.Path
;
28 import org
.apache
.hadoop
.hbase
.HConstants
;
29 import org
.apache
.hadoop
.hbase
.TableName
;
30 import org
.apache
.hadoop
.hbase
.client
.RegionInfo
;
31 import org
.apache
.hadoop
.hbase
.client
.RegionInfoBuilder
;
32 import org
.apache
.hadoop
.hbase
.mob
.MobConstants
;
33 import org
.apache
.hadoop
.hbase
.regionserver
.HRegion
;
34 import org
.apache
.hadoop
.hbase
.regionserver
.StoreFileInfo
;
35 import org
.apache
.hadoop
.hbase
.util
.FSUtils
;
36 import org
.apache
.hadoop
.hbase
.util
.HFileArchiveUtil
;
37 import org
.apache
.hadoop
.hbase
.util
.Pair
;
38 import org
.apache
.yetus
.audience
.InterfaceAudience
;
39 import org
.slf4j
.Logger
;
40 import org
.slf4j
.LoggerFactory
;
43 * HFileLink describes a link to an hfile.
45 * An hfile can be served from a region or from the hfile archive directory (/hbase/.archive)
46 * HFileLink allows to access the referenced hfile regardless of the location where it is.
48 * <p>Searches for hfiles in the following order and locations:
50 * <li>/hbase/table/region/cf/hfile</li>
51 * <li>/hbase/.archive/table/region/cf/hfile</li>
54 * The link checks first in the original path if it is not present
55 * it fallbacks to the archived path.
57 @InterfaceAudience.Private
58 @edu.umd
.cs
.findbugs
.annotations
.SuppressWarnings(value
="EQ_DOESNT_OVERRIDE_EQUALS",
59 justification
="To be fixed but warning suppressed for now")
60 public class HFileLink
extends FileLink
{
61 private static final Logger LOG
= LoggerFactory
.getLogger(HFileLink
.class);
64 * A non-capture group, for HFileLink, so that this can be embedded.
65 * The HFileLink describe a link to an hfile in a different table/region
66 * and the name is in the form: table=region-hfile.
68 * Table name is ([\p{IsAlphabetic}\p{Digit}][\p{IsAlphabetic}\p{Digit}.-]*), so '=' is an invalid
69 * character for the table name.
70 * Region name is ([a-f0-9]+), so '-' is an invalid character for the region name.
71 * HFile is ([0-9a-f]+(?:_SeqId_[0-9]+_)?) covering the plain hfiles (uuid)
72 * and the bulk loaded (_SeqId_[0-9]+_) hfiles.
74 * <p>Here is an example name: /hbase/test/0123/cf/testtb=4567-abcd where 'testtb' is table name
75 * and '4567' is region name and 'abcd' is filename.
77 public static final String LINK_NAME_REGEX
=
78 String
.format("(?:(?:%s=)?)%s=%s-%s",
79 TableName
.VALID_NAMESPACE_REGEX
, TableName
.VALID_TABLE_QUALIFIER_REGEX
,
80 RegionInfoBuilder
.ENCODED_REGION_NAME_REGEX
, StoreFileInfo
.HFILE_NAME_REGEX
);
82 /** Define the HFile Link name parser in the form of: table=region-hfile */
83 //made package private for testing
84 static final Pattern LINK_NAME_PATTERN
=
85 Pattern
.compile(String
.format("^(?:(%s)(?:\\=))?(%s)=(%s)-(%s)$",
86 TableName
.VALID_NAMESPACE_REGEX
, TableName
.VALID_TABLE_QUALIFIER_REGEX
,
87 RegionInfoBuilder
.ENCODED_REGION_NAME_REGEX
, StoreFileInfo
.HFILE_NAME_REGEX
));
90 * The pattern should be used for hfile and reference links
91 * that can be found in /hbase/table/region/family/
93 private static final Pattern REF_OR_HFILE_LINK_PATTERN
=
94 Pattern
.compile(String
.format("^(?:(%s)(?:=))?(%s)=(%s)-(.+)$",
95 TableName
.VALID_NAMESPACE_REGEX
, TableName
.VALID_TABLE_QUALIFIER_REGEX
,
96 RegionInfoBuilder
.ENCODED_REGION_NAME_REGEX
));
98 private final Path archivePath
;
99 private final Path originPath
;
100 private final Path mobPath
;
101 private final Path tempPath
;
104 * Dead simple hfile link constructor
106 public HFileLink(final Path originPath
, final Path tempPath
, final Path mobPath
,
107 final Path archivePath
) {
108 this.tempPath
= tempPath
;
109 this.originPath
= originPath
;
110 this.mobPath
= mobPath
;
111 this.archivePath
= archivePath
;
112 setLocations(originPath
, tempPath
, mobPath
, archivePath
);
117 * @param conf {@link Configuration} from which to extract specific archive locations
118 * @param hFileLinkPattern The path ending with a HFileLink pattern. (table=region-hfile)
119 * @throws IOException on unexpected error.
121 public static final HFileLink
buildFromHFileLinkPattern(Configuration conf
, Path hFileLinkPattern
)
123 return buildFromHFileLinkPattern(FSUtils
.getRootDir(conf
),
124 HFileArchiveUtil
.getArchivePath(conf
), hFileLinkPattern
);
130 * @param rootDir Path to the root directory where hbase files are stored
131 * @param archiveDir Path to the hbase archive directory
132 * @param hFileLinkPattern The path of the HFile Link.
134 public final static HFileLink
buildFromHFileLinkPattern(final Path rootDir
,
135 final Path archiveDir
,
136 final Path hFileLinkPattern
) {
137 Path hfilePath
= getHFileLinkPatternRelativePath(hFileLinkPattern
);
138 Path tempPath
= new Path(new Path(rootDir
, HConstants
.HBASE_TEMP_DIRECTORY
), hfilePath
);
139 Path originPath
= new Path(rootDir
, hfilePath
);
140 Path mobPath
= new Path(new Path(rootDir
, MobConstants
.MOB_DIR_NAME
), hfilePath
);
141 Path archivePath
= new Path(archiveDir
, hfilePath
);
142 return new HFileLink(originPath
, tempPath
, mobPath
, archivePath
);
146 * Create an HFileLink relative path for the table/region/family/hfile location
147 * @param table Table name
148 * @param region Region Name
149 * @param family Family Name
150 * @param hfile HFile Name
151 * @return the relative Path to open the specified table/region/family/hfile link
153 public static Path
createPath(final TableName table
, final String region
,
154 final String family
, final String hfile
) {
155 if (HFileLink
.isHFileLink(hfile
)) {
156 return new Path(family
, hfile
);
158 return new Path(family
, HFileLink
.createHFileLinkName(table
, region
, hfile
));
162 * Create an HFileLink instance from table/region/family/hfile location
163 * @param conf {@link Configuration} from which to extract specific archive locations
164 * @param table Table name
165 * @param region Region Name
166 * @param family Family Name
167 * @param hfile HFile Name
168 * @return Link to the file with the specified table/region/family/hfile location
169 * @throws IOException on unexpected error.
171 public static HFileLink
build(final Configuration conf
, final TableName table
,
172 final String region
, final String family
, final String hfile
)
174 return HFileLink
.buildFromHFileLinkPattern(conf
, createPath(table
, region
, family
, hfile
));
178 * @return the origin path of the hfile.
180 public Path
getOriginPath() {
181 return this.originPath
;
185 * @return the path of the archived hfile.
187 public Path
getArchivePath() {
188 return this.archivePath
;
192 * @return the path of the mob hfiles.
194 public Path
getMobPath() {
199 * @param path Path to check.
200 * @return True if the path is a HFileLink.
202 public static boolean isHFileLink(final Path path
) {
203 return isHFileLink(path
.getName());
208 * @param fileName File name to check.
209 * @return True if the path is a HFileLink.
211 public static boolean isHFileLink(String fileName
) {
212 Matcher m
= LINK_NAME_PATTERN
.matcher(fileName
);
213 if (!m
.matches()) return false;
214 return m
.groupCount() > 2 && m
.group(4) != null && m
.group(3) != null && m
.group(2) != null;
218 * Convert a HFileLink path to a table relative path.
219 * e.g. the link: /hbase/test/0123/cf/testtb=4567-abcd
220 * becomes: /hbase/testtb/4567/cf/abcd
222 * @param path HFileLink path
223 * @return Relative table path
224 * @throws IOException on unexpected error.
226 private static Path
getHFileLinkPatternRelativePath(final Path path
) {
227 // table=region-hfile
228 Matcher m
= REF_OR_HFILE_LINK_PATTERN
.matcher(path
.getName());
230 throw new IllegalArgumentException(path
.getName() + " is not a valid HFileLink pattern!");
233 // Convert the HFileLink name into a real table/region/cf/hfile path.
234 TableName tableName
= TableName
.valueOf(m
.group(1), m
.group(2));
235 String regionName
= m
.group(3);
236 String hfileName
= m
.group(4);
237 String familyName
= path
.getParent().getName();
238 Path tableDir
= FSUtils
.getTableDir(new Path("./"), tableName
);
239 return new Path(tableDir
, new Path(regionName
, new Path(familyName
,
244 * Get the HFile name of the referenced link
246 * @param fileName HFileLink file name
247 * @return the name of the referenced HFile
249 public static String
getReferencedHFileName(final String fileName
) {
250 Matcher m
= REF_OR_HFILE_LINK_PATTERN
.matcher(fileName
);
252 throw new IllegalArgumentException(fileName
+ " is not a valid HFileLink name!");
258 * Get the Region name of the referenced link
260 * @param fileName HFileLink file name
261 * @return the name of the referenced Region
263 public static String
getReferencedRegionName(final String fileName
) {
264 Matcher m
= REF_OR_HFILE_LINK_PATTERN
.matcher(fileName
);
266 throw new IllegalArgumentException(fileName
+ " is not a valid HFileLink name!");
272 * Get the Table name of the referenced link
274 * @param fileName HFileLink file name
275 * @return the name of the referenced Table
277 public static TableName
getReferencedTableName(final String fileName
) {
278 Matcher m
= REF_OR_HFILE_LINK_PATTERN
.matcher(fileName
);
280 throw new IllegalArgumentException(fileName
+ " is not a valid HFileLink name!");
282 return(TableName
.valueOf(m
.group(1), m
.group(2)));
286 * Create a new HFileLink name
288 * @param hfileRegionInfo - Linked HFile Region Info
289 * @param hfileName - Linked HFile name
290 * @return file name of the HFile Link
292 public static String
createHFileLinkName(final RegionInfo hfileRegionInfo
,
293 final String hfileName
) {
294 return createHFileLinkName(hfileRegionInfo
.getTable(),
295 hfileRegionInfo
.getEncodedName(), hfileName
);
299 * Create a new HFileLink name
301 * @param tableName - Linked HFile table name
302 * @param regionName - Linked HFile region name
303 * @param hfileName - Linked HFile name
304 * @return file name of the HFile Link
306 public static String
createHFileLinkName(final TableName tableName
,
307 final String regionName
, final String hfileName
) {
308 String s
= String
.format("%s=%s-%s",
309 tableName
.getNameAsString().replace(TableName
.NAMESPACE_DELIM
, '='),
310 regionName
, hfileName
);
315 * Create a new HFileLink
317 * <p>It also adds a back-reference to the hfile back-reference directory
318 * to simplify the reference-count and the cleaning process.
320 * @param conf {@link Configuration} to read for the archive directory name
321 * @param fs {@link FileSystem} on which to write the HFileLink
322 * @param dstFamilyPath - Destination path (table/region/cf/)
323 * @param hfileRegionInfo - Linked HFile Region Info
324 * @param hfileName - Linked HFile name
325 * @return true if the file is created, otherwise the file exists.
326 * @throws IOException on file or parent directory creation failure
328 public static boolean create(final Configuration conf
, final FileSystem fs
,
329 final Path dstFamilyPath
, final RegionInfo hfileRegionInfo
,
330 final String hfileName
) throws IOException
{
331 return create(conf
, fs
, dstFamilyPath
, hfileRegionInfo
, hfileName
, true);
335 * Create a new HFileLink
337 * <p>It also adds a back-reference to the hfile back-reference directory
338 * to simplify the reference-count and the cleaning process.
340 * @param conf {@link Configuration} to read for the archive directory name
341 * @param fs {@link FileSystem} on which to write the HFileLink
342 * @param dstFamilyPath - Destination path (table/region/cf/)
343 * @param hfileRegionInfo - Linked HFile Region Info
344 * @param hfileName - Linked HFile name
345 * @param createBackRef - Whether back reference should be created. Defaults to true.
346 * @return true if the file is created, otherwise the file exists.
347 * @throws IOException on file or parent directory creation failure
349 public static boolean create(final Configuration conf
, final FileSystem fs
,
350 final Path dstFamilyPath
, final RegionInfo hfileRegionInfo
,
351 final String hfileName
, final boolean createBackRef
) throws IOException
{
352 TableName linkedTable
= hfileRegionInfo
.getTable();
353 String linkedRegion
= hfileRegionInfo
.getEncodedName();
354 return create(conf
, fs
, dstFamilyPath
, linkedTable
, linkedRegion
, hfileName
, createBackRef
);
358 * Create a new HFileLink
360 * <p>It also adds a back-reference to the hfile back-reference directory
361 * to simplify the reference-count and the cleaning process.
363 * @param conf {@link Configuration} to read for the archive directory name
364 * @param fs {@link FileSystem} on which to write the HFileLink
365 * @param dstFamilyPath - Destination path (table/region/cf/)
366 * @param linkedTable - Linked Table Name
367 * @param linkedRegion - Linked Region Name
368 * @param hfileName - Linked HFile name
369 * @return true if the file is created, otherwise the file exists.
370 * @throws IOException on file or parent directory creation failure
372 public static boolean create(final Configuration conf
, final FileSystem fs
,
373 final Path dstFamilyPath
, final TableName linkedTable
, final String linkedRegion
,
374 final String hfileName
) throws IOException
{
375 return create(conf
, fs
, dstFamilyPath
, linkedTable
, linkedRegion
, hfileName
, true);
379 * Create a new HFileLink
381 * <p>It also adds a back-reference to the hfile back-reference directory
382 * to simplify the reference-count and the cleaning process.
384 * @param conf {@link Configuration} to read for the archive directory name
385 * @param fs {@link FileSystem} on which to write the HFileLink
386 * @param dstFamilyPath - Destination path (table/region/cf/)
387 * @param linkedTable - Linked Table Name
388 * @param linkedRegion - Linked Region Name
389 * @param hfileName - Linked HFile name
390 * @param createBackRef - Whether back reference should be created. Defaults to true.
391 * @return true if the file is created, otherwise the file exists.
392 * @throws IOException on file or parent directory creation failure
394 public static boolean create(final Configuration conf
, final FileSystem fs
,
395 final Path dstFamilyPath
, final TableName linkedTable
, final String linkedRegion
,
396 final String hfileName
, final boolean createBackRef
) throws IOException
{
397 String familyName
= dstFamilyPath
.getName();
398 String regionName
= dstFamilyPath
.getParent().getName();
399 String tableName
= FSUtils
.getTableName(dstFamilyPath
.getParent().getParent())
402 String name
= createHFileLinkName(linkedTable
, linkedRegion
, hfileName
);
403 String refName
= createBackReferenceName(tableName
, regionName
);
405 // Make sure the destination directory exists
406 fs
.mkdirs(dstFamilyPath
);
408 // Make sure the FileLink reference directory exists
409 Path archiveStoreDir
= HFileArchiveUtil
.getStoreArchivePath(conf
,
410 linkedTable
, linkedRegion
, familyName
);
411 Path backRefPath
= null;
413 Path backRefssDir
= getBackReferencesDir(archiveStoreDir
, hfileName
);
414 fs
.mkdirs(backRefssDir
);
416 // Create the reference for the link
417 backRefPath
= new Path(backRefssDir
, refName
);
418 fs
.createNewFile(backRefPath
);
422 return fs
.createNewFile(new Path(dstFamilyPath
, name
));
423 } catch (IOException e
) {
424 LOG
.error("couldn't create the link=" + name
+ " for " + dstFamilyPath
, e
);
425 // Revert the reference if the link creation failed
427 fs
.delete(backRefPath
, false);
434 * Create a new HFileLink starting from a hfileLink name
436 * <p>It also adds a back-reference to the hfile back-reference directory
437 * to simplify the reference-count and the cleaning process.
439 * @param conf {@link Configuration} to read for the archive directory name
440 * @param fs {@link FileSystem} on which to write the HFileLink
441 * @param dstFamilyPath - Destination path (table/region/cf/)
442 * @param hfileLinkName - HFileLink name (it contains hfile-region-table)
443 * @return true if the file is created, otherwise the file exists.
444 * @throws IOException on file or parent directory creation failure
446 public static boolean createFromHFileLink(final Configuration conf
, final FileSystem fs
,
447 final Path dstFamilyPath
, final String hfileLinkName
)
449 return createFromHFileLink(conf
, fs
, dstFamilyPath
, hfileLinkName
, true);
453 * Create a new HFileLink starting from a hfileLink name
455 * <p>It also adds a back-reference to the hfile back-reference directory
456 * to simplify the reference-count and the cleaning process.
458 * @param conf {@link Configuration} to read for the archive directory name
459 * @param fs {@link FileSystem} on which to write the HFileLink
460 * @param dstFamilyPath - Destination path (table/region/cf/)
461 * @param hfileLinkName - HFileLink name (it contains hfile-region-table)
462 * @param createBackRef - Whether back reference should be created. Defaults to true.
463 * @return true if the file is created, otherwise the file exists.
464 * @throws IOException on file or parent directory creation failure
466 public static boolean createFromHFileLink(final Configuration conf
, final FileSystem fs
,
467 final Path dstFamilyPath
, final String hfileLinkName
, final boolean createBackRef
)
469 Matcher m
= LINK_NAME_PATTERN
.matcher(hfileLinkName
);
471 throw new IllegalArgumentException(hfileLinkName
+ " is not a valid HFileLink name!");
473 return create(conf
, fs
, dstFamilyPath
, TableName
.valueOf(m
.group(1), m
.group(2)),
474 m
.group(3), m
.group(4), createBackRef
);
478 * Create the back reference name
480 //package-private for testing
481 static String
createBackReferenceName(final String tableNameStr
,
482 final String regionName
) {
484 return regionName
+ "." + tableNameStr
.replace(TableName
.NAMESPACE_DELIM
, '=');
488 * Get the full path of the HFile referenced by the back reference
490 * @param rootDir root hbase directory
491 * @param linkRefPath Link Back Reference path
492 * @return full path of the referenced hfile
494 public static Path
getHFileFromBackReference(final Path rootDir
, final Path linkRefPath
) {
495 Pair
<TableName
, String
> p
= parseBackReferenceName(linkRefPath
.getName());
496 TableName linkTableName
= p
.getFirst();
497 String linkRegionName
= p
.getSecond();
499 String hfileName
= getBackReferenceFileName(linkRefPath
.getParent());
500 Path familyPath
= linkRefPath
.getParent().getParent();
501 Path regionPath
= familyPath
.getParent();
502 Path tablePath
= regionPath
.getParent();
504 String linkName
= createHFileLinkName(FSUtils
.getTableName(tablePath
),
505 regionPath
.getName(), hfileName
);
506 Path linkTableDir
= FSUtils
.getTableDir(rootDir
, linkTableName
);
507 Path regionDir
= HRegion
.getRegionDir(linkTableDir
, linkRegionName
);
508 return new Path(new Path(regionDir
, familyPath
.getName()), linkName
);
511 public static Pair
<TableName
, String
> parseBackReferenceName(String name
) {
512 int separatorIndex
= name
.indexOf('.');
513 String linkRegionName
= name
.substring(0, separatorIndex
);
514 String tableSubstr
= name
.substring(separatorIndex
+ 1)
515 .replace('=', TableName
.NAMESPACE_DELIM
);
516 TableName linkTableName
= TableName
.valueOf(tableSubstr
);
517 return new Pair
<>(linkTableName
, linkRegionName
);
521 * Get the full path of the HFile referenced by the back reference
523 * @param conf {@link Configuration} to read for the archive directory name
524 * @param linkRefPath Link Back Reference path
525 * @return full path of the referenced hfile
526 * @throws IOException on unexpected error.
528 public static Path
getHFileFromBackReference(final Configuration conf
, final Path linkRefPath
)
530 return getHFileFromBackReference(FSUtils
.getRootDir(conf
), linkRefPath
);