1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.regionserver;
21
22 import java.io.FileNotFoundException;
23 import java.io.IOException;
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.hadoop.hbase.classification.InterfaceAudience;
30 import org.apache.hadoop.conf.Configuration;
31 import org.apache.hadoop.fs.FileStatus;
32 import org.apache.hadoop.fs.FileSystem;
33 import org.apache.hadoop.fs.Path;
34 import org.apache.hadoop.hbase.HDFSBlocksDistribution;
35 import org.apache.hadoop.hbase.io.FSDataInputStreamWrapper;
36 import org.apache.hadoop.hbase.io.HFileLink;
37 import org.apache.hadoop.hbase.io.HalfStoreFileReader;
38 import org.apache.hadoop.hbase.io.Reference;
39 import org.apache.hadoop.hbase.io.hfile.CacheConfig;
40 import org.apache.hadoop.hbase.util.FSUtils;
41
42
43
44
45 @InterfaceAudience.Private
46 public class StoreFileInfo {
47 private static final Log LOG = LogFactory.getLog(StoreFileInfo.class);
48
49
50
51
52
53 public static final String HFILE_NAME_REGEX = "[0-9a-f]+(?:_SeqId_[0-9]+_)?";
54
55
56 private static final Pattern HFILE_NAME_PATTERN =
57 Pattern.compile("^(" + HFILE_NAME_REGEX + ")");
58
59
60
61
62
63
64
65
66 private static final Pattern REF_NAME_PATTERN =
67 Pattern.compile(String.format("^(%s|%s)\\.(.+)$",
68 HFILE_NAME_REGEX, HFileLink.LINK_NAME_REGEX));
69
70
71 private Configuration conf;
72
73
74 private final FileSystem fs;
75
76
77 private HDFSBlocksDistribution hdfsBlocksDistribution = null;
78
79
80 private final Reference reference;
81
82
83 private final HFileLink link;
84
85 private final Path initialPath;
86
87 private RegionCoprocessorHost coprocessorHost;
88
89
90 private long createdTimestamp;
91
92
93
94
95
96
97
98 public StoreFileInfo(final Configuration conf, final FileSystem fs, final Path initialPath)
99 throws IOException {
100 assert fs != null;
101 assert initialPath != null;
102 assert conf != null;
103
104 this.fs = fs;
105 this.conf = conf;
106 this.initialPath = initialPath;
107 Path p = initialPath;
108 if (HFileLink.isHFileLink(p)) {
109
110 this.reference = null;
111 this.link = HFileLink.buildFromHFileLinkPattern(conf, p);
112 if (LOG.isTraceEnabled()) LOG.trace(p + " is a link");
113 } else if (isReference(p)) {
114 this.reference = Reference.read(fs, p);
115 Path referencePath = getReferredToFile(p);
116 if (HFileLink.isHFileLink(referencePath)) {
117
118 this.link = HFileLink.buildFromHFileLinkPattern(conf, referencePath);
119 } else {
120
121 this.link = null;
122 }
123 if (LOG.isTraceEnabled()) LOG.trace(p + " is a " + reference.getFileRegion() +
124 " reference to " + referencePath);
125 } else if (isHFile(p)) {
126
127 this.createdTimestamp = fs.getFileStatus(initialPath).getModificationTime();
128 this.reference = null;
129 this.link = null;
130 } else {
131 throw new IOException("path=" + p + " doesn't look like a valid StoreFile");
132 }
133 }
134
135
136
137
138
139
140
141 public StoreFileInfo(final Configuration conf, final FileSystem fs, final FileStatus fileStatus)
142 throws IOException {
143 this(conf, fs, fileStatus.getPath());
144 }
145
146
147
148
149
150
151
152 public StoreFileInfo(final Configuration conf, final FileSystem fs, final FileStatus fileStatus,
153 final HFileLink link)
154 throws IOException {
155 this.fs = fs;
156 this.conf = conf;
157
158 this.initialPath = (fileStatus == null) ? null : fileStatus.getPath();
159
160 this.reference = null;
161 this.link = link;
162 }
163
164
165
166
167
168
169
170
171
172 public StoreFileInfo(final Configuration conf, final FileSystem fs, final FileStatus fileStatus,
173 final Reference reference)
174 throws IOException {
175 this.fs = fs;
176 this.conf = conf;
177 this.initialPath = fileStatus.getPath();
178 this.createdTimestamp = fileStatus.getModificationTime();
179 this.reference = reference;
180 this.link = null;
181 }
182
183
184
185
186
187 public void setRegionCoprocessorHost(RegionCoprocessorHost coprocessorHost) {
188 this.coprocessorHost = coprocessorHost;
189 }
190
191
192
193
194
195 public Reference getReference() {
196 return this.reference;
197 }
198
199
200 public boolean isReference() {
201 return this.reference != null;
202 }
203
204
205 public boolean isTopReference() {
206 return this.reference != null && Reference.isTopFileRegion(this.reference.getFileRegion());
207 }
208
209
210 public boolean isLink() {
211 return this.link != null && this.reference == null;
212 }
213
214
215 public HDFSBlocksDistribution getHDFSBlockDistribution() {
216 return this.hdfsBlocksDistribution;
217 }
218
219
220
221
222
223
224
225 public StoreFile.Reader open(final FileSystem fs,
226 final CacheConfig cacheConf, final boolean canUseDropBehind) throws IOException {
227 FSDataInputStreamWrapper in;
228 FileStatus status;
229
230 final boolean doDropBehind = canUseDropBehind && cacheConf.shouldDropBehindCompaction();
231 if (this.link != null) {
232
233 in = new FSDataInputStreamWrapper(fs, this.link, doDropBehind);
234 status = this.link.getFileStatus(fs);
235 } else if (this.reference != null) {
236
237 Path referencePath = getReferredToFile(this.getPath());
238 in = new FSDataInputStreamWrapper(fs, referencePath,
239 doDropBehind);
240 status = fs.getFileStatus(referencePath);
241 } else {
242 in = new FSDataInputStreamWrapper(fs, this.getPath(),
243 doDropBehind);
244 status = fs.getFileStatus(initialPath);
245 }
246 long length = status.getLen();
247 hdfsBlocksDistribution = computeHDFSBlocksDistribution(fs);
248
249 StoreFile.Reader reader = null;
250 if (this.coprocessorHost != null) {
251 reader = this.coprocessorHost.preStoreFileReaderOpen(fs, this.getPath(), in, length,
252 cacheConf, reference);
253 }
254 if (reader == null) {
255 if (this.reference != null) {
256 reader = new HalfStoreFileReader(fs, this.getPath(), in, length, cacheConf, reference,
257 conf);
258 } else {
259 reader = new StoreFile.Reader(fs, status.getPath(), in, length, cacheConf, conf);
260 }
261 }
262 if (this.coprocessorHost != null) {
263 reader = this.coprocessorHost.postStoreFileReaderOpen(fs, this.getPath(), in, length,
264 cacheConf, reference, reader);
265 }
266 return reader;
267 }
268
269
270
271
272 public HDFSBlocksDistribution computeHDFSBlocksDistribution(final FileSystem fs)
273 throws IOException {
274
275
276
277 if (this.link != null) {
278 FileNotFoundException exToThrow = null;
279 for (int i = 0; i < this.link.getLocations().length; i++) {
280 try {
281 return computeHDFSBlocksDistributionInternal(fs);
282 } catch (FileNotFoundException ex) {
283
284 exToThrow = ex;
285 }
286 }
287 throw exToThrow;
288 } else {
289 return computeHDFSBlocksDistributionInternal(fs);
290 }
291 }
292
293 private HDFSBlocksDistribution computeHDFSBlocksDistributionInternal(final FileSystem fs)
294 throws IOException {
295 FileStatus status = getReferencedFileStatus(fs);
296 if (this.reference != null) {
297 return computeRefFileHDFSBlockDistribution(fs, reference, status);
298 } else {
299 return FSUtils.computeHDFSBlocksDistribution(fs, status, 0, status.getLen());
300 }
301 }
302
303
304
305
306
307
308 public FileStatus getReferencedFileStatus(final FileSystem fs) throws IOException {
309 FileStatus status;
310 if (this.reference != null) {
311 if (this.link != null) {
312 FileNotFoundException exToThrow = null;
313 for (int i = 0; i < this.link.getLocations().length; i++) {
314
315 try {
316 return link.getFileStatus(fs);
317 } catch (FileNotFoundException ex) {
318
319 exToThrow = ex;
320 }
321 }
322 throw exToThrow;
323 } else {
324
325 Path referencePath = getReferredToFile(this.getPath());
326 status = fs.getFileStatus(referencePath);
327 }
328 } else {
329 if (this.link != null) {
330 FileNotFoundException exToThrow = null;
331 for (int i = 0; i < this.link.getLocations().length; i++) {
332
333 try {
334 return link.getFileStatus(fs);
335 } catch (FileNotFoundException ex) {
336
337 exToThrow = ex;
338 }
339 }
340 throw exToThrow;
341 } else {
342 status = fs.getFileStatus(initialPath);
343 }
344 }
345 return status;
346 }
347
348
349 public Path getPath() {
350 return initialPath;
351 }
352
353
354 public FileStatus getFileStatus() throws IOException {
355 return getReferencedFileStatus(fs);
356 }
357
358
359 public long getModificationTime() throws IOException {
360 return getFileStatus().getModificationTime();
361 }
362
363 @Override
364 public String toString() {
365 return this.getPath() +
366 (isReference() ? "-" + getReferredToFile(this.getPath()) + "-" + reference : "");
367 }
368
369
370
371
372
373 public static boolean isHFile(final Path path) {
374 return isHFile(path.getName());
375 }
376
377 public static boolean isHFile(final String fileName) {
378 Matcher m = HFILE_NAME_PATTERN.matcher(fileName);
379 return m.matches() && m.groupCount() > 0;
380 }
381
382
383
384
385
386 public static boolean isReference(final Path path) {
387 return isReference(path.getName());
388 }
389
390
391
392
393
394 public static boolean isReference(final String name) {
395 Matcher m = REF_NAME_PATTERN.matcher(name);
396 return m.matches() && m.groupCount() > 1;
397 }
398
399
400
401
402 public long getCreatedTimestamp() {
403 return createdTimestamp;
404 }
405
406
407
408
409
410
411
412
413 public static Path getReferredToFile(final Path p) {
414 Matcher m = REF_NAME_PATTERN.matcher(p.getName());
415 if (m == null || !m.matches()) {
416 LOG.warn("Failed match of store file name " + p.toString());
417 throw new IllegalArgumentException("Failed match of store file name " +
418 p.toString());
419 }
420
421
422 String otherRegion = m.group(2);
423
424 Path tableDir = p.getParent().getParent().getParent();
425 String nameStrippedOfSuffix = m.group(1);
426 if (LOG.isDebugEnabled()) {
427 LOG.debug("reference '" + p + "' to region=" + otherRegion
428 + " hfile=" + nameStrippedOfSuffix);
429 }
430
431
432
433 return new Path(new Path(new Path(tableDir, otherRegion),
434 p.getParent().getName()), nameStrippedOfSuffix);
435 }
436
437
438
439
440
441
442 public static boolean validateStoreFileName(final String fileName) {
443 if (HFileLink.isHFileLink(fileName) || isReference(fileName))
444 return(true);
445 return !fileName.contains("-");
446 }
447
448
449
450
451
452
453 public static boolean isValid(final FileStatus fileStatus)
454 throws IOException {
455 final Path p = fileStatus.getPath();
456
457 if (fileStatus.isDirectory())
458 return false;
459
460
461
462
463 if (!HFileLink.isHFileLink(p) && fileStatus.getLen() <= 0) {
464 LOG.warn("Skipping " + p + " because it is empty. HBASE-646 DATA LOSS?");
465 return false;
466 }
467
468 return validateStoreFileName(p.getName());
469 }
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484 private static HDFSBlocksDistribution computeRefFileHDFSBlockDistribution(
485 final FileSystem fs, final Reference reference, final FileStatus status)
486 throws IOException {
487 if (status == null) {
488 return null;
489 }
490
491 long start = 0;
492 long length = 0;
493
494 if (Reference.isTopFileRegion(reference.getFileRegion())) {
495 start = status.getLen()/2;
496 length = status.getLen() - status.getLen()/2;
497 } else {
498 start = 0;
499 length = status.getLen()/2;
500 }
501 return FSUtils.computeHDFSBlocksDistribution(fs, status, start, length);
502 }
503
504 @Override
505 public boolean equals(Object that) {
506 if (this == that) return true;
507 if (that == null) return false;
508
509 if (!(that instanceof StoreFileInfo)) return false;
510
511 StoreFileInfo o = (StoreFileInfo)that;
512 if (initialPath != null && o.initialPath == null) return false;
513 if (initialPath == null && o.initialPath != null) return false;
514 if (initialPath != o.initialPath && initialPath != null
515 && !initialPath.equals(o.initialPath)) return false;
516
517 if (reference != null && o.reference == null) return false;
518 if (reference == null && o.reference != null) return false;
519 if (reference != o.reference && reference != null
520 && !reference.equals(o.reference)) return false;
521
522 if (link != null && o.link == null) return false;
523 if (link == null && o.link != null) return false;
524 if (link != o.link && link != null && !link.equals(o.link)) return false;
525
526 return true;
527 };
528
529
530 @Override
531 public int hashCode() {
532 int hash = 17;
533 hash = hash * 31 + ((reference == null) ? 0 : reference.hashCode());
534 hash = hash * 31 + ((initialPath == null) ? 0 : initialPath.hashCode());
535 hash = hash * 31 + ((link == null) ? 0 : link.hashCode());
536 return hash;
537 }
538 }