(final Path corruptPath, final FileSystem fs,
final Configuration conf, final List<Long> footerOffsets, final String backup)
| 554 | } |
| 555 | |
| 556 | private static void recoverFile(final Path corruptPath, final FileSystem fs, |
| 557 | final Configuration conf, final List<Long> footerOffsets, final String backup) |
| 558 | throws IOException { |
| 559 | |
| 560 | // first recover the file to .recovered file and then once successful rename it to actual file |
| 561 | Path recoveredPath = getRecoveryFile(corruptPath); |
| 562 | |
| 563 | // make sure that file does not exist |
| 564 | if (fs.exists(recoveredPath)) { |
| 565 | fs.delete(recoveredPath, false); |
| 566 | } |
| 567 | |
| 568 | // if there are no valid footers, the file should still be readable so create an empty orc file |
| 569 | if (footerOffsets == null || footerOffsets.isEmpty()) { |
| 570 | System.err.println("No readable footers found. Creating empty orc file."); |
| 571 | TypeDescription schema = TypeDescription.createStruct(); |
| 572 | Writer writer = OrcFile.createWriter(recoveredPath, |
| 573 | OrcFile.writerOptions(conf).setSchema(schema)); |
| 574 | writer.close(); |
| 575 | } else { |
| 576 | FSDataInputStream fdis = fs.open(corruptPath); |
| 577 | FileStatus fileStatus = fs.getFileStatus(corruptPath); |
| 578 | // read corrupt file and copy it to recovered file until last valid footer |
| 579 | FSDataOutputStream fdos = fs.create(recoveredPath, true, |
| 580 | conf.getInt("io.file.buffer.size", 4096), |
| 581 | fileStatus.getReplication(), |
| 582 | fileStatus.getBlockSize()); |
| 583 | try { |
| 584 | long fileLen = footerOffsets.get(footerOffsets.size() - 1); |
| 585 | long remaining = fileLen; |
| 586 | |
| 587 | while (remaining > 0) { |
| 588 | int toRead = (int) Math.min(DEFAULT_BLOCK_SIZE, remaining); |
| 589 | byte[] data = new byte[toRead]; |
| 590 | long startPos = fileLen - remaining; |
| 591 | fdis.readFully(startPos, data, 0, toRead); |
| 592 | fdos.write(data); |
| 593 | System.err.println("Copying data to recovery file - startPos: " + startPos + |
| 594 | " toRead: " + toRead + " remaining: " + remaining); |
| 595 | remaining = remaining - toRead; |
| 596 | } |
| 597 | } catch (Exception e) { |
| 598 | fs.delete(recoveredPath, false); |
| 599 | throw new IOException(e); |
| 600 | } finally { |
| 601 | fdis.close(); |
| 602 | fdos.close(); |
| 603 | } |
| 604 | } |
| 605 | |
| 606 | // validate the recovered file once again and start moving corrupt files to backup folder |
| 607 | if (isReadable(recoveredPath, conf, Long.MAX_VALUE)) { |
| 608 | Path backupDataPath; |
| 609 | Path backupDirPath; |
| 610 | Path relativeCorruptPath; |
| 611 | String scheme = corruptPath.toUri().getScheme(); |
| 612 | String authority = corruptPath.toUri().getAuthority(); |
| 613 |
no test coverage detected