/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.raid; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintStream; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.HashSet; import java.util.concurrent.atomic.AtomicLong; import java.io.FileWriter; import java.io.BufferedWriter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.raid.protocol.PolicyInfo; /** * Check for files that have a replication factor of less than 3 * And which do not have a parity file created for them */ public class MissingParityFiles { private Configuration conf; private boolean directoryTraversalShuffle; private int directoryTraversalThreads; private short replicationLimit = 3; private boolean restoreReplication; public MissingParityFiles(Configuration conf) { this(conf, false); } public MissingParityFiles(Configuration conf, boolean restoreReplication) { this.conf = conf; this.directoryTraversalShuffle = conf.getBoolean(RaidNode.RAID_DIRECTORYTRAVERSAL_SHUFFLE, true); this.directoryTraversalThreads = conf.getInt(RaidNode.RAID_DIRECTORYTRAVERSAL_THREADS, 4); this.replicationLimit = (short) conf.getInt("raid.missingparity.replicationlimit", 3); this.restoreReplication = restoreReplication; } public void findMissingParityFiles(Path root, PrintStream out) throws IOException { FileSystem fs = root.getFileSystem(conf); List<Path> allPaths = Arrays.asList(root); DirectoryTraversal.Filter filter = new MissingParityFilter(conf, replicationLimit); boolean allowUseStandby = false; DirectoryTraversal traversal = new DirectoryTraversal("Missing Parity Retriever ", allPaths, fs, filter, directoryTraversalThreads, directoryTraversalShuffle, allowUseStandby); FileStatus newFile; while ((newFile = traversal.next()) != DirectoryTraversal.FINISH_TOKEN) { Path filePath = newFile.getPath(); out.println(filePath.toUri().getPath()); if (restoreReplication) { System.err.println("Setting replication=" + replicationLimit + " for " + filePath); fs.setReplication(filePath, replicationLimit); } } } static class MissingParityFilter implements DirectoryTraversal.Filter { Configuration conf; int limit; MissingParityFilter(Configuration conf, int limit) throws IOException { this.conf = conf; this.limit = limit; } @Override public boolean check(FileStatus f) throws IOException { if (f.isDir()) return false; Path filePath = f.getPath(); if (isParityFile(filePath)) { return false; } if (f.getReplication() < limit) { boolean found = false; for (Codec c : Codec.getCodecs()) { ParityFilePair parityPair = ParityFilePair.getParityFile(c, f, conf); if (parityPair != null) { found = true; break; } } if (!found) { return true; } } return false; } public boolean isParityFile(Path filePath) { String pathStr = filePath.toUri().getPath(); for (Codec c : Codec.getCodecs()) { if (pathStr.startsWith(c.getParityPrefix())) { return true; } } return false; } } }