/**
* 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.fs.shell;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.fs.PathIsDirectoryException;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
/**
* Truncates a file to a new size
*/
@InterfaceAudience.Private
@InterfaceStability.Unstable
public class Truncate extends FsCommand {
public static void registerCommands(CommandFactory factory) {
factory.addClass(Truncate.class, "-truncate");
}
public static final String NAME = "truncate";
public static final String USAGE = "[-w] <length> <path> ...";
public static final String DESCRIPTION =
"Truncate all files that match the specified file pattern to the " +
"specified length.\n" +
"-w: Requests that the command wait for block recovery to complete, " +
"if necessary.";
protected long newLength = -1;
protected List<PathData> waitList = new LinkedList<>();
protected boolean waitOpt = false;
@Override
protected void processOptions(LinkedList<String> args) throws IOException {
CommandFormat cf = new CommandFormat(2, Integer.MAX_VALUE, "w");
cf.parse(args);
waitOpt = cf.getOpt("w");
try {
newLength = Long.parseLong(args.removeFirst());
} catch(NumberFormatException nfe) {
displayWarning("Illegal length, a non-negative integer expected");
throw nfe;
}
if(newLength < 0) {
throw new IllegalArgumentException("length must be >= 0");
}
}
@Override
protected void processArguments(LinkedList<PathData> args)
throws IOException {
super.processArguments(args);
if (waitOpt) waitForRecovery();
}
@Override
protected void processPath(PathData item) throws IOException {
if(item.stat.isDirectory()) {
throw new PathIsDirectoryException(item.toString());
}
long oldLength = item.stat.getLen();
if(newLength > oldLength) {
throw new IllegalArgumentException(
"Cannot truncate to a larger file size. Current size: " + oldLength +
", truncate size: " + newLength + ".");
}
if(item.fs.truncate(item.path, newLength)) {
out.println("Truncated " + item + " to length: " + newLength);
}
else if(waitOpt) {
waitList.add(item);
}
else {
out.println("Truncating " + item + " to length: " + newLength + ". " +
"Wait for block recovery to complete before further updating this " +
"file.");
}
}
/**
* Wait for all files in waitList to have length equal to newLength.
*/
private void waitForRecovery() throws IOException {
for(PathData item : waitList) {
out.println("Waiting for " + item + " ...");
out.flush();
for(;;) {
item.refreshStatus();
if(item.stat.getLen() == newLength) break;
try {Thread.sleep(1000);} catch(InterruptedException ignored) {}
}
out.println("Truncated " + item + " to length: " + newLength);
out.flush();
}
}
}