1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.io;
20
21 import java.io.IOException;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.hadoop.classification.InterfaceAudience;
28 import org.apache.hadoop.conf.Configuration;
29 import org.apache.hadoop.fs.FileSystem;
30 import org.apache.hadoop.fs.Path;
31 import org.apache.hadoop.hbase.TableName;
32 import org.apache.hadoop.hbase.HConstants;
33 import org.apache.hadoop.hbase.HRegionInfo;
34 import org.apache.hadoop.hbase.regionserver.HRegion;
35 import org.apache.hadoop.hbase.regionserver.StoreFileInfo;
36 import org.apache.hadoop.hbase.util.FSUtils;
37 import org.apache.hadoop.hbase.util.HFileArchiveUtil;
38 import org.apache.hadoop.hbase.util.Pair;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 @InterfaceAudience.Private
56 public class HFileLink extends FileLink {
57 private static final Log LOG = LogFactory.getLog(HFileLink.class);
58
59
60
61
62
63
64
65
66
67
68
69 public static final String LINK_NAME_REGEX =
70 String.format("(?:(?:%s=)?)%s=%s-%s",
71 TableName.VALID_NAMESPACE_REGEX, TableName.VALID_TABLE_QUALIFIER_REGEX,
72 HRegionInfo.ENCODED_REGION_NAME_REGEX, StoreFileInfo.HFILE_NAME_REGEX);
73
74
75
76 static final Pattern LINK_NAME_PATTERN =
77 Pattern.compile(String.format("^(?:(%s)(?:\\=))?(%s)=(%s)-(%s)$",
78 TableName.VALID_NAMESPACE_REGEX, TableName.VALID_TABLE_QUALIFIER_REGEX,
79 HRegionInfo.ENCODED_REGION_NAME_REGEX, StoreFileInfo.HFILE_NAME_REGEX));
80
81
82
83
84
85 private static final Pattern REF_OR_HFILE_LINK_PATTERN =
86 Pattern.compile(String.format("^(?:(%s)(?:=))?(%s)=(%s)-(.+)$",
87 TableName.VALID_NAMESPACE_REGEX, TableName.VALID_TABLE_QUALIFIER_REGEX,
88 HRegionInfo.ENCODED_REGION_NAME_REGEX));
89
90 private final Path archivePath;
91 private final Path originPath;
92 private final Path tempPath;
93
94
95
96
97
98
99 public HFileLink(Configuration conf, Path path) throws IOException {
100 this(FSUtils.getRootDir(conf), HFileArchiveUtil.getArchivePath(conf), path);
101 }
102
103
104
105
106
107
108 public HFileLink(final Path rootDir, final Path archiveDir, final Path path) {
109 Path hfilePath = getRelativeTablePath(path);
110 this.tempPath = new Path(new Path(rootDir, HConstants.HBASE_TEMP_DIRECTORY), hfilePath);
111 this.originPath = new Path(rootDir, hfilePath);
112 this.archivePath = new Path(archiveDir, hfilePath);
113 setLocations(originPath, tempPath, archivePath);
114 }
115
116
117
118
119
120
121
122
123
124 public static Path createPath(final TableName table, final String region,
125 final String family, final String hfile) {
126 if (HFileLink.isHFileLink(hfile)) {
127 return new Path(family, hfile);
128 }
129 return new Path(family, HFileLink.createHFileLinkName(table, region, hfile));
130 }
131
132
133
134
135
136
137
138
139
140
141
142 public static HFileLink create(final Configuration conf, final TableName table,
143 final String region, final String family, final String hfile) throws IOException {
144 return new HFileLink(conf, createPath(table, region, family, hfile));
145 }
146
147
148
149
150 public Path getOriginPath() {
151 return this.originPath;
152 }
153
154
155
156
157 public Path getArchivePath() {
158 return this.archivePath;
159 }
160
161
162
163
164
165 public static boolean isHFileLink(final Path path) {
166 return isHFileLink(path.getName());
167 }
168
169
170
171
172
173
174 public static boolean isHFileLink(String fileName) {
175 Matcher m = LINK_NAME_PATTERN.matcher(fileName);
176 if (!m.matches()) return false;
177 return m.groupCount() > 2 && m.group(4) != null && m.group(3) != null && m.group(2) != null;
178 }
179
180
181
182
183
184
185
186
187
188
189 private static Path getRelativeTablePath(final Path path) {
190
191 Matcher m = REF_OR_HFILE_LINK_PATTERN.matcher(path.getName());
192 if (!m.matches()) {
193 throw new IllegalArgumentException(path.getName() + " is not a valid HFileLink name!");
194 }
195
196
197 TableName tableName = TableName.valueOf(m.group(1), m.group(2));
198 String regionName = m.group(3);
199 String hfileName = m.group(4);
200 String familyName = path.getParent().getName();
201 Path tableDir = FSUtils.getTableDir(new Path("./"), tableName);
202 return new Path(tableDir, new Path(regionName, new Path(familyName,
203 hfileName)));
204 }
205
206
207
208
209
210
211
212 public static String getReferencedHFileName(final String fileName) {
213 Matcher m = REF_OR_HFILE_LINK_PATTERN.matcher(fileName);
214 if (!m.matches()) {
215 throw new IllegalArgumentException(fileName + " is not a valid HFileLink name!");
216 }
217 return(m.group(4));
218 }
219
220
221
222
223
224
225
226 public static String getReferencedRegionName(final String fileName) {
227 Matcher m = REF_OR_HFILE_LINK_PATTERN.matcher(fileName);
228 if (!m.matches()) {
229 throw new IllegalArgumentException(fileName + " is not a valid HFileLink name!");
230 }
231 return(m.group(3));
232 }
233
234
235
236
237
238
239
240 public static TableName getReferencedTableName(final String fileName) {
241 Matcher m = REF_OR_HFILE_LINK_PATTERN.matcher(fileName);
242 if (!m.matches()) {
243 throw new IllegalArgumentException(fileName + " is not a valid HFileLink name!");
244 }
245 return(TableName.valueOf(m.group(1), m.group(2)));
246 }
247
248
249
250
251 public boolean exists(final FileSystem fs) throws IOException {
252 return fs.exists(this.originPath) ||
253 fs.exists(this.tempPath) ||
254 fs.exists(this.archivePath);
255 }
256
257
258
259
260
261
262
263
264 public static String createHFileLinkName(final HRegionInfo hfileRegionInfo,
265 final String hfileName) {
266 return createHFileLinkName(hfileRegionInfo.getTable(),
267 hfileRegionInfo.getEncodedName(), hfileName);
268 }
269
270
271
272
273
274
275
276
277
278 public static String createHFileLinkName(final TableName tableName,
279 final String regionName, final String hfileName) {
280 String s = String.format("%s=%s-%s",
281 tableName.getNameAsString().replace(TableName.NAMESPACE_DELIM, '='),
282 regionName, hfileName);
283 return s;
284 }
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300 public static boolean create(final Configuration conf, final FileSystem fs,
301 final Path dstFamilyPath, final HRegionInfo hfileRegionInfo,
302 final String hfileName) throws IOException {
303 TableName linkedTable = hfileRegionInfo.getTable();
304 String linkedRegion = hfileRegionInfo.getEncodedName();
305 return create(conf, fs, dstFamilyPath, linkedTable, linkedRegion, hfileName);
306 }
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323 public static boolean create(final Configuration conf, final FileSystem fs,
324 final Path dstFamilyPath, final TableName linkedTable, final String linkedRegion,
325 final String hfileName) throws IOException {
326 String familyName = dstFamilyPath.getName();
327 String regionName = dstFamilyPath.getParent().getName();
328 String tableName = FSUtils.getTableName(dstFamilyPath.getParent().getParent())
329 .getNameAsString();
330
331 String name = createHFileLinkName(linkedTable, linkedRegion, hfileName);
332 String refName = createBackReferenceName(tableName, regionName);
333
334
335 fs.mkdirs(dstFamilyPath);
336
337
338 Path archiveStoreDir = HFileArchiveUtil.getStoreArchivePath(conf,
339 linkedTable, linkedRegion, familyName);
340 Path backRefssDir = getBackReferencesDir(archiveStoreDir, hfileName);
341 fs.mkdirs(backRefssDir);
342
343
344 Path backRefPath = new Path(backRefssDir, refName);
345 fs.createNewFile(backRefPath);
346 try {
347
348 return fs.createNewFile(new Path(dstFamilyPath, name));
349 } catch (IOException e) {
350 LOG.error("couldn't create the link=" + name + " for " + dstFamilyPath, e);
351
352 fs.delete(backRefPath, false);
353 throw e;
354 }
355 }
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370 public static boolean createFromHFileLink(final Configuration conf, final FileSystem fs,
371 final Path dstFamilyPath, final String hfileLinkName) throws IOException {
372 Matcher m = LINK_NAME_PATTERN.matcher(hfileLinkName);
373 if (!m.matches()) {
374 throw new IllegalArgumentException(hfileLinkName + " is not a valid HFileLink name!");
375 }
376 return create(conf, fs, dstFamilyPath, TableName.valueOf(m.group(1), m.group(2)),
377 m.group(3), m.group(4));
378 }
379
380
381
382
383
384 static String createBackReferenceName(final String tableNameStr,
385 final String regionName) {
386
387 return regionName + "." + tableNameStr.replace(TableName.NAMESPACE_DELIM, '=');
388 }
389
390
391
392
393
394
395
396
397
398 public static Path getHFileFromBackReference(final Path rootDir, final Path linkRefPath) {
399 Pair<TableName, String> p = parseBackReferenceName(linkRefPath.getName());
400 TableName linkTableName = p.getFirst();
401 String linkRegionName = p.getSecond();
402
403 String hfileName = getBackReferenceFileName(linkRefPath.getParent());
404 Path familyPath = linkRefPath.getParent().getParent();
405 Path regionPath = familyPath.getParent();
406 Path tablePath = regionPath.getParent();
407
408 String linkName = createHFileLinkName(FSUtils.getTableName(tablePath),
409 regionPath.getName(), hfileName);
410 Path linkTableDir = FSUtils.getTableDir(rootDir, linkTableName);
411 Path regionDir = HRegion.getRegionDir(linkTableDir, linkRegionName);
412 return new Path(new Path(regionDir, familyPath.getName()), linkName);
413 }
414
415 static Pair<TableName, String> parseBackReferenceName(String name) {
416 int separatorIndex = name.indexOf('.');
417 String linkRegionName = name.substring(0, separatorIndex);
418 String tableSubstr = name.substring(separatorIndex + 1)
419 .replace('=', TableName.NAMESPACE_DELIM);
420 TableName linkTableName = TableName.valueOf(tableSubstr);
421 return new Pair<TableName, String>(linkTableName, linkRegionName);
422 }
423
424
425
426
427
428
429
430
431
432 public static Path getHFileFromBackReference(final Configuration conf, final Path linkRefPath)
433 throws IOException {
434 return getHFileFromBackReference(FSUtils.getRootDir(conf), linkRefPath);
435 }
436
437 }