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