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.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.FileNotFoundException;
27 import java.util.List;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.hadoop.hbase.classification.InterfaceAudience;
32 import org.apache.hadoop.fs.CanUnbuffer;
33 import org.apache.hadoop.fs.FSDataInputStream;
34 import org.apache.hadoop.fs.FileSystem;
35 import org.apache.hadoop.fs.FileStatus;
36 import org.apache.hadoop.fs.Path;
37 import org.apache.hadoop.fs.PositionedReadable;
38 import org.apache.hadoop.fs.Seekable;
39 import org.apache.hadoop.hbase.util.FSUtils;
40 import org.apache.hadoop.ipc.RemoteException;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 @InterfaceAudience.Private
93 public class FileLink {
94 private static final Log LOG = LogFactory.getLog(FileLink.class);
95
96
97 public static final String BACK_REFERENCES_DIRECTORY_PREFIX = ".links-";
98
99
100
101
102
103 private static class FileLinkInputStream extends InputStream
104 implements Seekable, PositionedReadable, CanUnbuffer {
105 private FSDataInputStream in = null;
106 private Path currentPath = null;
107 private long pos = 0;
108
109 private final FileLink fileLink;
110 private final int bufferSize;
111 private final FileSystem fs;
112
113 public FileLinkInputStream(final FileSystem fs, final FileLink fileLink)
114 throws IOException {
115 this(fs, fileLink, FSUtils.getDefaultBufferSize(fs));
116 }
117
118 public FileLinkInputStream(final FileSystem fs, final FileLink fileLink, int bufferSize)
119 throws IOException {
120 this.bufferSize = bufferSize;
121 this.fileLink = fileLink;
122 this.fs = fs;
123
124 this.in = tryOpen();
125 }
126
127 @Override
128 public int read() throws IOException {
129 int res;
130 try {
131 res = in.read();
132 } catch (FileNotFoundException e) {
133 res = tryOpen().read();
134 } catch (NullPointerException e) {
135 res = tryOpen().read();
136 } catch (AssertionError e) {
137 res = tryOpen().read();
138 }
139 if (res > 0) pos += 1;
140 return res;
141 }
142
143 @Override
144 public int read(byte[] b) throws IOException {
145 return read(b, 0, b.length);
146 }
147
148 @Override
149 public int read(byte[] b, int off, int len) throws IOException {
150 int n;
151 try {
152 n = in.read(b, off, len);
153 } catch (FileNotFoundException e) {
154 n = tryOpen().read(b, off, len);
155 } catch (NullPointerException e) {
156 n = tryOpen().read(b, off, len);
157 } catch (AssertionError e) {
158 n = tryOpen().read(b, off, len);
159 }
160 if (n > 0) pos += n;
161 assert(in.getPos() == pos);
162 return n;
163 }
164
165 @Override
166 public int read(long position, byte[] buffer, int offset, int length) throws IOException {
167 int n;
168 try {
169 n = in.read(position, buffer, offset, length);
170 } catch (FileNotFoundException e) {
171 n = tryOpen().read(position, buffer, offset, length);
172 } catch (NullPointerException e) {
173 n = tryOpen().read(position, buffer, offset, length);
174 } catch (AssertionError e) {
175 n = tryOpen().read(position, buffer, offset, length);
176 }
177 return n;
178 }
179
180 @Override
181 public void readFully(long position, byte[] buffer) throws IOException {
182 readFully(position, buffer, 0, buffer.length);
183 }
184
185 @Override
186 public void readFully(long position, byte[] buffer, int offset, int length) throws IOException {
187 try {
188 in.readFully(position, buffer, offset, length);
189 } catch (FileNotFoundException e) {
190 tryOpen().readFully(position, buffer, offset, length);
191 } catch (NullPointerException e) {
192 tryOpen().readFully(position, buffer, offset, length);
193 } catch (AssertionError e) {
194 tryOpen().readFully(position, buffer, offset, length);
195 }
196 }
197
198 @Override
199 public long skip(long n) throws IOException {
200 long skipped;
201
202 try {
203 skipped = in.skip(n);
204 } catch (FileNotFoundException e) {
205 skipped = tryOpen().skip(n);
206 } catch (NullPointerException e) {
207 skipped = tryOpen().skip(n);
208 } catch (AssertionError e) {
209 skipped = tryOpen().skip(n);
210 }
211
212 if (skipped > 0) pos += skipped;
213 return skipped;
214 }
215
216 @Override
217 public int available() throws IOException {
218 try {
219 return in.available();
220 } catch (FileNotFoundException e) {
221 return tryOpen().available();
222 } catch (NullPointerException e) {
223 return tryOpen().available();
224 } catch (AssertionError e) {
225 return tryOpen().available();
226 }
227 }
228
229 @Override
230 public void seek(long pos) throws IOException {
231 try {
232 in.seek(pos);
233 } catch (FileNotFoundException e) {
234 tryOpen().seek(pos);
235 } catch (NullPointerException e) {
236 tryOpen().seek(pos);
237 } catch (AssertionError e) {
238 tryOpen().seek(pos);
239 }
240 this.pos = pos;
241 }
242
243 @Override
244 public long getPos() throws IOException {
245 return pos;
246 }
247
248 @Override
249 public boolean seekToNewSource(long targetPos) throws IOException {
250 boolean res;
251 try {
252 res = in.seekToNewSource(targetPos);
253 } catch (FileNotFoundException e) {
254 res = tryOpen().seekToNewSource(targetPos);
255 } catch (NullPointerException e) {
256 res = tryOpen().seekToNewSource(targetPos);
257 } catch (AssertionError e) {
258 res = tryOpen().seekToNewSource(targetPos);
259 }
260 if (res) pos = targetPos;
261 return res;
262 }
263
264 @Override
265 public void close() throws IOException {
266 in.close();
267 }
268
269 @Override
270 public synchronized void mark(int readlimit) {
271 }
272
273 @Override
274 public synchronized void reset() throws IOException {
275 throw new IOException("mark/reset not supported");
276 }
277
278 @Override
279 public boolean markSupported() {
280 return false;
281 }
282
283 @Override
284 public void unbuffer() {
285 if (in == null) {
286 return;
287 }
288 in.unbuffer();
289 }
290
291
292
293
294
295
296
297 private FSDataInputStream tryOpen() throws IOException {
298 for (Path path: fileLink.getLocations()) {
299 if (path.equals(currentPath)) continue;
300 try {
301 in = fs.open(path, bufferSize);
302 if (pos != 0) in.seek(pos);
303 assert(in.getPos() == pos) : "Link unable to seek to the right position=" + pos;
304 if (LOG.isTraceEnabled()) {
305 if (currentPath == null) {
306 LOG.debug("link open path=" + path);
307 } else {
308 LOG.trace("link switch from path=" + currentPath + " to path=" + path);
309 }
310 }
311 currentPath = path;
312 return(in);
313 } catch (FileNotFoundException e) {
314
315 } catch (RemoteException re) {
316 IOException ioe = re.unwrapRemoteException(FileNotFoundException.class);
317 if (!(ioe instanceof FileNotFoundException)) throw re;
318 }
319 }
320 throw new FileNotFoundException(this.fileLink.toString());
321 }
322 }
323
324 private Path[] locations = null;
325
326 protected FileLink() {
327 this.locations = null;
328 }
329
330
331
332
333
334 public FileLink(Path originPath, Path... alternativePaths) {
335 setLocations(originPath, alternativePaths);
336 }
337
338
339
340
341 public FileLink(final Collection<Path> locations) {
342 this.locations = locations.toArray(new Path[locations.size()]);
343 }
344
345
346
347
348 public Path[] getLocations() {
349 return locations;
350 }
351
352 @Override
353 public String toString() {
354 StringBuilder str = new StringBuilder(getClass().getSimpleName());
355 str.append(" locations=[");
356 for (int i = 0; i < locations.length; ++i) {
357 if (i > 0) str.append(", ");
358 str.append(locations[i].toString());
359 }
360 str.append("]");
361 return str.toString();
362 }
363
364
365
366
367 public boolean exists(final FileSystem fs) throws IOException {
368 for (int i = 0; i < locations.length; ++i) {
369 if (fs.exists(locations[i])) {
370 return true;
371 }
372 }
373 return false;
374 }
375
376
377
378
379 public Path getAvailablePath(FileSystem fs) throws IOException {
380 for (int i = 0; i < locations.length; ++i) {
381 if (fs.exists(locations[i])) {
382 return locations[i];
383 }
384 }
385 throw new FileNotFoundException(toString());
386 }
387
388
389
390
391
392
393
394
395 public FileStatus getFileStatus(FileSystem fs) throws IOException {
396 for (int i = 0; i < locations.length; ++i) {
397 try {
398 return fs.getFileStatus(locations[i]);
399 } catch (FileNotFoundException e) {
400
401 }
402 }
403 throw new FileNotFoundException(toString());
404 }
405
406
407
408
409
410
411
412
413
414
415
416 public FSDataInputStream open(final FileSystem fs) throws IOException {
417 return new FSDataInputStream(new FileLinkInputStream(fs, this));
418 }
419
420
421
422
423
424
425
426
427
428
429
430
431 public FSDataInputStream open(final FileSystem fs, int bufferSize) throws IOException {
432 return new FSDataInputStream(new FileLinkInputStream(fs, this, bufferSize));
433 }
434
435
436
437
438
439 protected void setLocations(Path originPath, Path... alternativePaths) {
440 assert this.locations == null : "Link locations already set";
441
442 List<Path> paths = new ArrayList<Path>(alternativePaths.length +1);
443 if (originPath != null) {
444 paths.add(originPath);
445 }
446
447 for (int i = 0; i < alternativePaths.length; i++) {
448 if (alternativePaths[i] != null) {
449 paths.add(alternativePaths[i]);
450 }
451 }
452 this.locations = paths.toArray(new Path[0]);
453 }
454
455
456
457
458
459
460
461
462
463
464
465 public static Path getBackReferencesDir(final Path storeDir, final String fileName) {
466 return new Path(storeDir, BACK_REFERENCES_DIRECTORY_PREFIX + fileName);
467 }
468
469
470
471
472
473
474
475 public static String getBackReferenceFileName(final Path dirPath) {
476 return dirPath.getName().substring(BACK_REFERENCES_DIRECTORY_PREFIX.length());
477 }
478
479
480
481
482
483
484
485 public static boolean isBackReferencesDir(final Path dirPath) {
486 if (dirPath == null) return false;
487 return dirPath.getName().startsWith(BACK_REFERENCES_DIRECTORY_PREFIX);
488 }
489
490 @Override
491 public boolean equals(Object obj) {
492 if (obj == null) {
493 return false;
494 }
495
496
497
498 if (this.getClass().equals(obj.getClass())) {
499 return Arrays.equals(this.locations, ((FileLink) obj).locations);
500 }
501
502 return false;
503 }
504
505 @Override
506 public int hashCode() {
507 return Arrays.hashCode(locations);
508 }
509 }
510